Scala中的真实世界函数式编程

SOOOO …

半群,幺半群,单子,函子,镜头,变形,变形,箭……这些都听起来不错,经过一两次(或十次)的练习,你就能掌握它们的本质。 和Scalaz ,你可以免费得到它们。

然而,就现实世界的编程而言,我发现自己正在努力寻找这些概念的用法。 是的,当然,我总是在网上find一些人使用monads IO或斯卡拉镜头,但… …仍然…

我试图find的是某种模式的“规定性”方面的东西。 就像这样:“在这里,你正在试图解决这个问题 ,解决这个问题的一个好办法就是用这种方法来使用镜头!”

build议?


更新:按照这两行,有一两本书,会很棒(感谢Paul): Java核心库中的GoFdevise模式示例

在九月份,我重新讨论了monoids和applicative functors / monads通过scalaz.Validation的实际应用。 我在Scala Lift Off上发表了另外一个版本,其中重点更多地放在了validation上。 我会看第一个谈话,直到我开始validation,然后跳到第二个谈话(27分钟)。

还有一个我写的要点 ,它显示了如何在“实际”应用程序中使用validation 。 也就是说,如果你正在devise夜总会保镖软件。

函数式编程的关键是抽象和抽象的可组合性。 Monads,Arrows,Lenses,这些都是已经certificate是有用的抽象,主要是因为它们是可组合的。 你已经要求一个“规定性”的答案,但我会说不。 也许你不相信函数式编程很重要 ?

我相信StackOverflow上很多人会乐意尝试并帮助您解决FP方式的特定问题。 有一个东西的列表,你想遍历的列表,并build立一些结果? 使用折叠。 想要parsingXML? hxt使用箭头。 还有monads? 那么,大量的数据types变成Monad,所以了解它们,你会发现你可以操纵这些数据types的很多方法。 但是,它很难用空气拉扯例子,并说“镜头是正确的方式做到这一点”,“monoids是最好的方式来做到这一点”,等等。你如何解释给新手什么使用一个for循环是? 如果你想[空白],然后使用for循环[以这种方式]。 这是一般的; 有很多方法可以使用for循环。 这些FP抽象也是一样的。

如果你有多年的OOP经验,那么不要忘记你曾经是OOP的新手。 学习FP方法需要时间,更多的时间去了解一些OOP的倾向。 给它一些时间,你会发现一个function性方法的很多用途。

我认为你可以采取相反的做法,而不是写一小部分function时,问自己是否适用:半群,幺半群,单子,函子,透镜,变质,变形,箭头……大量的这些概念可以在当地使用。

一旦你开始了这条路线,你可能会看到使用无处不在。 对我来说,我有种半群,Monoid,Monads,Functors。 所以采取回答这个问题的例子如何填充具有新值的对象列表 。 这个问题的人是一个真正的用法(一个自我描述的小白)。 我试图用一种简单的方法来回答,但是我不得不搔痒,“这里有怪癖”。

现在抓它:使用foldMap和Int和List是foldMap的事实,并且在处理元组,地图和选项时保留monoid属性:

 // using scalaz listVar.sliding(2).toList.foldMap{ case List(prev, i) => Some(Map(i -> (1, Some(List(math.abs(i - prev)))))) case List(i) => Some(Map(i -> (1, None))) case _ => None }.map(_.mapValues{ case (count, gaps) => (count, gaps.map(_.min)) }) 

但是我不认为我会用硬核function编程来达到这个目的。 它更自然地认为这看起来更简单,如果我写这些 monoids结合的事实,斯卡拉有像foldMap实用方法。 有趣的是,当查看所得到的代码时,我不完全用monoid来思考。

你可能会喜欢Chris Marshall的这个演讲 。 他涵盖了几个斯卡拉的好东西 – 即Monoid和validation – 有很多实际的例子。 Ittay Dror写了一篇非常方便的文章 ,讲述Functor,Applicative Functor和Monad如何在实践中有用。 Eric Torreborre和Debasish Gosh的博客也有许多关于分类构造用例的post。

这个答案只是列出了一些链接,而不是在这里提供一些真实的内容。 (太懒了写)希望你发现它有帮助无论如何。

我了解你的情况,但你会发现要学习函数式编程,你需要根据你find的文档来调整你的观点,而不是相反。 幸运的是,在Scala中,你有可能逐渐成为function程序员。

为了回答你的问题并解释观点差异,我需要区分“types类”(monoids,functor,arrow),math上称为“结构”,以及generics操作或algorithm(变形或折叠,变形或展开等)。 这两者经常交互,因为许多通用操作都是为特定types的数据types定义的。

您寻找类似于devise模式的规定性答案:这个概念何时适用? 事实是,你确实看到了规定性的答案,而它们只是不同概念的定义。 问题(对你而言)是这些答案与devise模式本质上是不同的,但是这是有充分理由的。

一方面,genericsalgorithm不是devise模式,它提供了您编写代码的结构; 它们是用您可以直接应用的语言定义的抽象。 它们是您现在已经实现的通用algorithm的一般描述,但是是通过手工来实现的。 例如,无论何时通过扫描来计算列表的最大元素,都是对一个折叠进行硬编码; 当你总结元素时,你也是这样做的; 等等。 当您意识到这一点时,您可以通过调用适当的折叠函数来声明正在执行的操作的本质。 通过这种方式,您可以节省代码和错误(不会出现错误的机会),并且可以让读者省去读取所有必需的代码。

另一方面,结构不关心你想要达到的目标,而是关心你正在build模的实体的属性。 它们对自下而上的软件构build更有用,而不是自上而下:定义数据时,可以声明它是一个例如monoid。 稍后,在处理数据时,您有机会使用例如monoids的操作来实现处理。 在某些情况下,努力根据预定义的algorithmexpressionalgorithm是有用的。 例如,如果您需要将树简化为单个值,则折叠可以完成大部分或全部所需。 当然,你也可以声明你的数据types是monoid,当你需要一个generics的algorithm时, 但是你注意到越早,你就可以开始重用generics的通用algorithm。

最后的build议是,你可能会发现关于这些概念的大部分文档都是关于Haskell的,因为这种语言已经存在了更多的时间,并且以一种非常优雅的方式支持它们。 在这里推荐学习Haskell for Great Good ,一个适合初学者的Haskell课程,其中第11-14章介绍一些types类, Typeclassopedia (包含具体示例的各种文章的链接)。 编辑:最后,从Typeclassopedia采取的猿人的应用程序的一个例子是: http : 我并不是说Scala只有很less的文档,只是Haskell有更多的文档,而Haskell就是这些概念在编程中应用的地方。