就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the help center寻求指导。
9年前关闭。
下个月我将从事一个新的研发项目,该项目将采用函数式编程语言(我投票支持 Haskell,但现在 F# 获得了更多共识)。现在,我已经使用这些语言一段时间,并用它们开发了一些命令行工具,但这是一个相当大的项目,我正在努力提高我的函数式编程知识和技术。我也阅读了很多关于该主题的内容,但我找不到任何记录函数式编程世界中反模式的书籍或资源。
现在,学习反模式意味着 了解其他聪明人的失败 :在 OOP 中,我知道其中的一些,并且当通常是反模式的东西完全符合我的需求时,我有足够的经验来明智地选择。但我可以选择这个,因为我知道其他聪明人吸取的教训。
因此,我的问题是:有没有 记录 anti-patterns在函数式编程中?到目前为止,我所有的同事都告诉我他们不知道,但他们无法说明原因。
请don't turn this question in a list :这是一个 bool 问题,只需要一个证明来评估答案。例如,如果您是 Oleg Kiselyov,"is"就足够了,因为每个人都可以找到您关于该主题的文章。不过,请大方一点。
请注意,我正在寻找正式的反模式,而不是简单的坏习惯或坏做法。
来自 linked wikipedia article on Anti-Patterns :
... there must be at least two key elements present to formally distinguish an actual anti-pattern from a simple bad habit, bad practice, or bad idea:
- some repeated pattern of action, process or structure that initially appears to be beneficial, but ultimately produces more bad consequences than beneficial results, and
- an alternative solution exists that is clearly documented, proven in actual practice and repeatable.
此外,“记录在案”是指来自 的内容。权威作者或 知名来源 .
我习惯的语言是:
但我也可以调整有关以其他功能语言记录的反模式的知识。
我在网上搜索了很多,但我找到的所有资源要么与 OOP 相关,要么与函数布局相关(在函数开头定义变量,等等......)。
最佳答案
我见过的唯一反模式是过度单子(monad)化,因为单子(monad)非常有用,所以它介于不良实践和反模式之间。
假设你有一些属性(property) P
你希望你的某些对象是真实的。你可以用 P monad 来装饰你的对象(在 Scala 中,使用 REPL 中的 paste
来让对象和它的伙伴粘在一起):
class P[A](val value: A) {
def flatMap[B](f: A => P[B]): P[B] = f(value) // AKA bind, >>=
def map[B](f: A => B) = flatMap(f andThen P.pure) // (to keep `for` happy)
}
object P {
def pure[A](a: A) = new P(a) // AKA unit, return
}
好的,到目前为止一切顺利;我们骗了一点
value
一个 val
而不是让它成为一个comonad(如果这是我们想要的),但我们现在有一个方便的包装器,我们可以在其中包装任何东西。现在假设我们还有属性 Q
和 R
.class Q[A](val value: A) {
def flatMap[B](f: A => Q[B]): Q[B] = f(value)
def map[B](f: A => B) = flatMap(f andThen Q.pure)
}
object Q {
def pure[A](a: A) = new Q(a)
}
class R[A](val value: A) {
def flatMap[B](f: A => R[B]): R[B] = f(value)
def map[B](f: A => B) = flatMap(f andThen R.pure)
}
object R {
def pure[A](a: A) = new R(a)
}
所以我们装饰我们的对象:
class Foo { override def toString = "foo" }
val bippy = R.pure( Q.pure( P.pure( new Foo ) ) )
现在我们突然面临一大堆问题。如果我们有一个方法需要属性
Q
,我们如何得到它?def bar(qf: Q[Foo]) = qf.value.toString + "bar"
嗯,很明显
bar(bippy)
行不通。有traverse
或 swap
有效地翻转 monad 的操作,所以我们可以,如果我们定义 swap
以适当的方式,做类似的事情bippy.map(_.swap).map(_.map(bar))
取回我们的字符串(实际上是
R[P[String]]
)。但是我们现在已经 promise 为我们调用的每个方法做类似的事情。这通常是错误的做法。如果可能,您应该使用其他一些同样安全的抽象机制。例如,在 Scala 中,您还可以创建标记特征
trait X
trait Y
trait Z
val tweel = new Foo with X with Y with Z
def baz(yf: Foo with Y) = yf.toString + "baz"
baz(tweel)
哇!容易多了。现在非常重要的是要指出并非一切都更容易。例如,如果您开始操作
Foo
,则使用此方法您必须自己跟踪所有装饰器,而不是让单子(monad) map
/flatMap
为你而做。但是很多时候你不需要做一堆实物操作,那么深度嵌套的 monad 就是一种反模式。(注意:monadic 嵌套具有堆栈结构,而特征具有 set 结构;编译器没有内在的原因不能允许 set-like monad,但它不是典型的类型理论公式的自然构造。反模式是一个简单的结果是深堆栈难以使用。如果您为 monad(或 Haskell 中的标准 Monad 转换器集)实现所有 Forth 堆栈操作,它们可能会更容易一些。)
关于scala - 是否有任何记录在案的函数式编程反模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15848856/