函数式编程会增加代码的复杂性吗?[关闭]


17

在过去的一年中,我一直在编写Scala代码(来自Java背景)。我真的很喜欢如何使用val,case类,map / filter / lambda函数,隐式函数和类型推断来创建更简单,更简洁的代码。我主要将其用于基于Akka的应用程序。

今年,我和一个新团队一起在Scala项目中,他们非常喜欢函数式编程。他们大量使用Scalaz,并且代码到处都是应用程序,上下文边界,读取器/写入器/状态monad,甚至是将主要方法“包装”在I / O monad中。他们的理由是,这使编译器在断言代码正确且每个函数都没有副作用的情况下“为我们工作”。

即便如此,从我的角度来看,所有这些语法确实确实妨碍了业务逻辑。例如,可以使用“ MyBusinessObject”类型,也可以使用“ List [MyBusinessObject]”,“ Option [MyBusinessObject]”或“ Future [MyBusinessObject]”类型。它们都有明确的含义和目的。另一方面,代码如下:

def method[M[_]: Applicative] = {
  case (a, b) => (ca[M](a) |@| cb[M](b)) {
    case t @ (ra, rb) =>
      if (ra.result && rb.result) t.right
      else t.left
  }
}

它会增加程序的复杂性吗?还是我不习惯这种编程方式?


6
您客观上可以回答的问题是什么?
Deer Hunter

1
看起来它会导致大量带有一个或两个字母变量名称的代码。看起来有点像APL。那不是补充。
user949300 2014年

3
我从去年开始与Haskell一起玩。它看起来极其复杂的时候,当我不明白像钻营,函子,单子等概念.. Haskell是类似于Scalaz,它有很多的短,象征性的功能,如中>>=<$>,这意味着什么,直到你知道他们做什么。但是,在了解了它们的含义之后,他们现在非常自然而迅速地向我阅读。并不是一个真正的答案,而只是我对这种事情的客观经验。我也使用Scala,但是没有使用Scalaz库的经验。
KChaloux 2014年

3
您只是不熟悉惯用语。对于许多功能代码,@ user949300短变量并不是真正的问题(请考虑一下数学样式约定!)。另请阅读Tony Morris的博客,以更深入地讨论如何更好地传达含义,类型或冗长的变量名。
Andres F.

3
@ user949300:短变量名在本地是首选的,在功能和命令式世界中是相同的(您不会写for(i=0; i<7; ++i) { trivialOperation(i); }一些笨拙的trivialOperationCount变量,对吗?)现在,具有模式匹配功能的编程语言有时会在其中引入更多变量只是在OO中写出访问器方法调用。结果通常更简洁;也许有点不言自明,但是查找数据声明通常会使它很快变得清晰。静态类型有很大帮助,这与APL不同。
leftaboutabout

Answers:


37

这与函数式编程无关 -您可以在任何其他编程语言的上下文中找到这种情况-开发人员非常喜欢“其”语言的高级构造,以至于他们忽略了任何有关可读性的常识,并使事情变得简单。我在C,C ++,Perl,Java,C#,Basic和其他非功能语言中遇到过这种情况。不是函数式编程会增加代码的复杂性,程序员会这样做。

不要误会我的意思,我不建议您避免使用高级语言功能-但是在给定的上下文中找到合适的平衡很重要。当编写一个通用库供全世界超过100,000个开发人员使用时,有多种不同的适用方法,如为本地办公室编写单个报告生成器时。


7
它与社区也有很多关系。对于具有Java或C#背景的开发人员来说,代码几乎是无法理解的(他/她的社区也不会理解)。但是,例如,如果您编写Haskell,并且不使用monad,applicatives,functorctors等,那么您就会感到该语言的社区感到困惑。代码的“自然性”不是固有的,而是相对于其社区和既定惯例的。
Andres F.

1
这很难看到,因为我们大多数人来自命令式背景,这有时使我们对自然是错误的假设。
Andres F.

只需看一下SLT C ++库,对于业余爱好者来说,它可以被编写为更具可读性
棘手的怪胎

@ratchetfreak:我想你是说STL。我认为这是一个很好的例子(确实,我在回答时就牢记了这一点)。当您是STL程序员时,使用模板元编程非常有意义,因为它使STL更可重用。而且必须维护该代码的人员通常也用于模板元编程。在整个标准业务应用程序中以类似STL的方式使用模板元编程会轻易导致过于复杂且难以维护的代码。毫无疑问,即使在业务应用中,TMP也可以很好地解决(很少)情况。
Doc Brown

@DocBrown是的诵读困难症是在错误的时间开始的,但是说实话,如果我有半点时间(比现在多得多的时间),我可以重写许多函数体,以提高可读性。
棘轮怪胎2014年

7

我想说,您不习惯他们编码的方式至少是其中的一部分。我的情况与您相似(从C#到F#,并与具有Haskell背景的人一起工作),虽然我发现这是一种有趣的经历,但我确实有一些时候会把头撞在墙上,特别是复杂的无点函数组合,只是想了解那里发生的事情。这是一种文化的东西。

至于这个特殊的代码是否增加了程序的复杂性-我不知道。同意通用代码本身可能很复杂。但这是一个实用程序,而不是业务逻辑的一部分。如果您想知道它是使代码库更复杂还是更简单,那么您就必须想象一下,如果没有那段代码,它的外观将是怎样的。这种通用结构通常很复杂,但它们本身很复杂,但您可以将其放在一个屏幕上。同时,它们使整个代码库更加简单。单子尤其如此。

再说一次,也可能是“为艺术而艺术”的案例,就像@Doc Brown建议的那样。也不能排除它。


5

我认为,一般而言,函数式编程通过消除可变状态来降低复杂度,从而减少了试图理解代码段的工作方式时必须考虑的情况。

但是,函数式编程可以实现更高程度的抽象,并且高度抽象的代码非常有用,但也很难理解,因为从定义上讲,它与您通常用来指导理解的上下文不同。您对业务对象的评论“它们都有明确的含义和目的”无疑是正确的,但实际上反映了这样一种事实,即逻辑非常针对您已经了解的需求和上下文。像Monad这样的结构的存在使您可以毫不费力地制作出非常有用的东西,但是网络上充斥着试图解释Monad是什么的页面。那是您的抽象。

另外,Scalaz是由长期食用和呼吸FP的人们撰写的;他们想将Haskell中可用的功能引入Scala。在这样做的过程中,他们没有试图进行教学。Scalaz使用的词汇和风格对作者来说似乎清晰明了,但对初学者却陌生。考虑到他们的Haskell背景,对于我们其他人来说,令人困惑的方法似乎是如此明显,以至于他们甚至都不愿发表评论。

此外,作为一种功能编程语言,Scala有一些缺点(部分是由于JVM有缺点),在某些情况下,这迫使Scalaz作者编写难看的代码。例如,缺少通用的尾部呼叫消除功能迫使在某些代码中使用蹦床,而缺少“种类系统”会使类型签名复杂化。

最后,Scalaz善用自己。可以认为这是其强大功能的标志,但是对于未启动的开发人员来说,这可能会使源代码困惑—您查看的任何随机代码段都可能会利用其他看起来与您无关的东西。

等一下 而这种可能的帮助。


-4

它会增加程序的复杂性,还是仅仅是您不习惯这种编程方式?

您为什么认为这些可能性不一样?

熟悉特定编程语言的人可以阅读编写良好的代码。以前从未见过任何编程语言的学童可以阅读和理解某些语言(BASIC,Pascal等)。

如果有人在其他语言上有经验并且在Scala中有经验(我认为他在Scalaz工作了至少一周,并且有同事来解释棘手的事情)仍然感到困惑;那就证明它增加了复杂性。


11
这根本不是真的:"Well written code can be read by people who aren't familiar with the specific programming language."
Andres F.

@安德列斯:的确是这样。编写良好的代码将把业务逻辑与实现细节分开,并且业务逻辑应该是可读的,因为它所做的大部分工作都是直接调用命名良好的辅助函数。当然,这些助手可能会使用各种语言功能,并且需要丰富的语言和库经验才能理解。
Ben Voigt 2014年

4
我相信以下是惯用的APL :x[⍋x←6?40]。您觉得呢?我肯定不会知道……
bdesham

3
@Brendan仅在相同的范式内(即使那样,有时也没有)。例如,Prolog,Java和APL是如此不同,以至于我会争辩说,如果您只了解其中一种(而没有其他语言),则无论您对第一种语言的了解程度如何,您都无法阅读其他两种语言。(以bdesham为例,很严重,如果您不了解APL,您应该如何解释“圣诞树”?)
Izkata 2014年

1
布伦丹,您对写得好的定义是不规范的。写得好总是与语言及其社区有关。如果没有错误,使用X语言编写的程序就很好,对于特定的受众来说,它是高效且清晰的!顺便说一句,这通常适用于书面语言:始终了解您的听众。适合(例如)科学论文的内容可能不适合发送给妈妈的电子邮件。
Andres F.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.