我逐渐学习 Haskell,甚至感觉掌握了单子的要领。然而,仍有很多更奇特的东西我几乎无法理解,如 Arrows(箭头)、Applicative(应用)等。虽然从我看到的 Haskell 代码中获取了一些片段,但找到一个真正解释它们的教程会很有帮助(似乎有数十个关于单子的教程...但所有的教程好像只是在单子之后完成!)
我逐渐学习 Haskell,甚至感觉掌握了单子的要领。然而,仍有很多更奇特的东西我几乎无法理解,如 Arrows(箭头)、Applicative(应用)等。虽然从我看到的 Haskell 代码中获取了一些片段,但找到一个真正解释它们的教程会很有帮助(似乎有数十个关于单子的教程...但所有的教程好像只是在单子之后完成!)
以下是我在掌握单子后发现有用的一些资源:
最重要的是,深入挖掘你发现自己正在使用的任何Hackage库的代码。如果它们在语法、习惯用法或扩展方面做了一些你不理解的事情,请查找相关资料。
Applicative
比Monad
更简单。我最近在其他地方说了一些关于它的事情,但要点是它涉及增强的Functor
,可以将函数提升到其中。要了解Applicative
,您可以尝试编写使用Parsec而不使用do
符号的内容——我的经验是,对于直接的解析器,应用程序样式比单调样式更有效。
Arrow
是一种非常抽象的处理类似函数(类型之间的“箭头”)的方法。除非你偶然发现自然具有Arrow
属性的东西,否则很难理解。曾经我在编写带有反馈循环的交互状态机时重新发明了Control.Arrow
的一半(效果不佳)。
虽然您没有提到它,但一个常常被低估的强大类型类是谦逊的Monoid
。可以在许多地方找到类似于单调结构的结构。例如,请查看monoids package。
Monad
回到Applicative
,Functor
和Monoid
是一个好的选择,我建议按相反的顺序(从Monoid
开始)。然后再回到Monad
并查看Arrow
。我敢打赌,将它放入更广泛的上下文中,你会更好地理解Monad
。Monad
有很多神奇的想法。它只是另一种类型类,即接口加代数定律。 - ConalMonoid
。它可能是最简单的结构,真正展示了代数思维的力量,而且很多其他东西都是基于对monoid的变化定义的。我认为我实际上会将Category
与Functor
或Applicative
并列,尽管我会把Arrow
留到后面。 - C. A. McCannCategory
的事情。我完全同意您的观点。简单而广泛适用。 - Conal像Monad
、Applicative
、Arrow
、Functor
这样的类型类很棒,它们甚至比函数通用性更能改变您对代码的思考方式。但是有一个普遍的误解,即Haskell的“下一步”是学习更多的类型类和控制流程结构方式。下一步是决定您想要编写什么,并尝试编写它,探索您需要的内容。
即使您理解了Monads,这也并不意味着您已经掌握了使用monadically结构化代码的表面。使用解析器组合库进行实验,或者编写自己的解析器组合库。探索为什么适用符号有时更容易。探索为什么将自己限制在应用程序解析器上可能更有效。
看看逻辑或数学问题,并探索实现回溯的方法--深度优先,广度优先等等。探索ListT和LogicT以及ChoiceT之间的区别。看看continuations。
或者做完全不同的事情!
迄今为止,你能做的最重要的事情就是探索更多的Hackage。与Haskell的各种奇特特性搏斗可能会让你找到改进某些问题的解决方案,而Hackage上的库将极大地扩展你的工具集。
Haskell生态系统最好的部分在于你可以平衡学习精确新抽象技术和学习如何使用Hackage上可用的巨大工具。
开始编写代码。随着你的学习,你会学到必要的概念。
除了语言本身,要有效地使用Haskell,您需要学习一些现实世界中的工具和技术。需要考虑以下几点:
*) cabal-init 可以帮助您快速启动。
**) 目前,我最喜欢的 FFI 绑定工具是 bindings-DSL。
作为下一步单一的步骤(而不是半打“下一步”),我建议您学习编写自己的类型类。以下是一些简单的问题,可供您入门:
为QuickCheck编写一些有趣的实例声明。比如说,您想生成一些在某种程度上“有趣”的随机树。
接下来,请解决以下小问题:定义函数/\
、\/
和complement
(“与”、“或”和“非”),它们不仅可以应用于布尔值,还可以应用于任意元数的谓词。(如果您仔细查看,可以在SO上找到答案。)
写一个 Haskell 编译器 :-).
Arrows
和Applicative
也能很好地完成工作: GHC有接近10万行代码,我们甚至从来没有使用过单子变换器。 - Simon Marlow