我将根据您在 Haskell 中的技能水平来订购本指南,从绝对的初学者到专家。请注意,此过程需要数月(数年?),因此相当长。
绝对初学者
首先,Haskell 可以做任何事情,只要有足够的技能。它非常快(在我的经验中仅落后于 C 和 C++),并且可以用于从模拟到服务器、gui 和 Web 应用程序的任何事情。
但是,对于 Haskell 初学者来说,有些问题比其他问题更容易编写。数学问题和列表处理程序是很好的候选对象,因为它们只需要最基本的 Haskell 知识即可编写。
一些学习 Haskell 基础知识的好指南是 Happy Learn Haskell Tutorial 和 Learn You a Haskell for Great Good 的前 6 章(或其 JupyterLab adaptation)。在阅读这些内容的同时,用你所知道的知识解决简单的问题是一个非常好的主意。
另外两个不错的资源是Haskell Programming from first principles 和Programming in Haskell。它们都附有每一章的练习,所以你有一些与你在最后几页学到的东西相匹配的小问题。
可以尝试的问题列表是haskell 99 problems page。这些从非常基础的开始,随着你的继续变得越来越困难。做很多这些都是很好的练习,因为它们可以让你练习递归和高阶函数的技能。我建议跳过任何需要随机性的问题,因为这在 Haskell 中有点困难。如果您想使用 QuickCheck 测试您的解决方案,请检查 this SO question(请参阅下面的中级)。
一旦你完成了其中的一些,你就可以继续做一些Project Euler 的问题。这些是按完成它们的人数排序的,这是一个相当好的难度指示。这些比以前的问题更能测试你的逻辑和 Haskell,但你应该仍然能够完成前几个问题。 Haskell 解决这些问题的一大优势是整数不受大小限制。要完成其中一些问题,阅读第 7 章和第 8 章的学习 Haskell 会很有帮助。
初学者
在那之后,您应该对递归和高阶函数有相当好的处理能力,所以现在是开始处理一些更现实世界的问题的好时机。一个很好的起点是Real World Haskell(在线书籍,也可以购买纸质版)。对于以前从未做过函数式编程/使用过递归的人来说,我发现前几章介绍得太快了。但是,通过练习之前的问题,您应该会发现它完全可以理解。
解决本书中的问题是学习如何在 Haskell 中管理抽象和构建可重用组件的好方法。这对于习惯于面向对象(oo)编程的人来说至关重要,因为普通的 oo 抽象方法(oo 类)不会出现在 Haskell 中(Haskell 有类型类,但它们与 oo 类非常不同,更像 oo 接口)。我认为跳过章节不是一个好主意,因为每个章节都会引入很多新的想法,这些想法会在后面的章节中使用。
一段时间后,您将进入第 14 章,可怕的单子章节 (dum dum dummmm)。几乎每个学习 Haskell 的人都很难理解 monad,因为这个概念非常抽象。我想不出另一种语言中的任何概念与函数式编程中的 monad 一样抽象。 Monads 允许将许多想法(例如 IO 操作、可能失败的计算、解析……)统一在一个想法下。因此,如果您在阅读了 monads 章节后并没有真正理解它们,请不要灰心。我发现阅读对 monad 的许多不同解释很有用。每个人都对问题提出了新的看法。这是一个非常好的list of monad tutorials。我强烈推荐All About Monads,但其他的也不错。
此外,这些概念需要一段时间才能真正融入其中。这既来自于使用,也来自于时间。我发现有时在问题上睡觉比其他任何事情都更有帮助!最终,这个想法会成功,你会想知道为什么你很难理解一个实际上非常简单的概念。当这种情况发生时真是太棒了,当它发生时,你可能会发现 Haskell 是你最喜欢的命令式编程语言 :)
为确保您完全理解 Haskell 类型系统,您应该尝试解决 20 intermediate haskell exercises。这些练习使用有趣的函数名称,如“furry”和“banana”,可以帮助您很好地理解一些基本的函数式编程概念(如果您还没有这些概念)。用一堆写满箭头、独角兽、香肠和毛茸茸的香蕉的纸来度过一个美好的夜晚。
中级
一旦你理解了 Monads,我认为你已经从一个初级 Haskell 程序员转变为一个中级 Haskell 程序员。那么从这里去哪里呢?我要推荐的第一件事(如果你还没有从学习 monad 中学到它们)是各种类型的 monad,例如 Reader、Writer 和 State。再一次,真实世界的 Haskell 和 All about monads 对此进行了很好的报道。要完成你的 monad 训练,学习 monad 转换器是必须的。这些让您可以将不同类型的 Monad(例如 Reader 和 State monad)组合成一个。刚开始这似乎没什么用,但在使用它们一段时间后,您会想知道没有它们您将如何生活。
现在,您可以根据需要完成真实世界的 Haskell 书籍。现在跳过章节并不重要,只要你有 monads down pat。只需选择您感兴趣的内容即可。
根据您现在所掌握的知识,您应该能够使用 cabal 上的大多数包(至少有文档记录的包...),以及 Haskell 附带的大多数库。可以尝试的有趣库列表如下:
-
Parsec:用于解析程序和文本。比使用正则表达式要好得多。优秀的文档,还有一个真实世界的 Haskell 章节。
-
QuickCheck: 一个很酷的测试程序。你要做的是编写一个应该始终为真的谓词(例如length (reverse lst) == length lst)。然后,您将谓词传递给 QuickCheck,它将生成大量随机值(在本例中为列表)并测试谓词对于所有结果是否为真。另请参阅online manual。
-
HUnit:Haskell 中的单元测试。
-
gtk2hs:Haskell 最流行的 gui 框架,让您编写 gtk 应用程序。
-
happstack:Haskell 的 Web 开发框架。不使用数据库,而是使用数据类型存储。非常好的文档(其他流行的框架是 snap 和 yesod)。
此外,您最终应该学习许多概念(例如 Monad 概念)。这将比第一次学习 Monad 更容易,因为您的大脑将习惯于处理所涉及的抽象级别。 Typeclassopedia 是了解这些高级概念以及它们如何组合在一起的一个很好的概述。
-
Applicative:类似于 Monads 的接口,但功能较弱。每个 Monad 都是 Applicative,但反之则不然。这很有用,因为有些类型是 Applicative 但不是 Monad。此外,使用 Applicative 函数编写的代码通常比使用 Monad 函数编写等效代码更具可组合性。请参阅Learn you a haskell 指南中的Functors, Applicative Functors and Monoids。
-
Foldable,Traversable:将列表的许多操作抽象化的类型类,以便将相同的功能应用于其他容器类型。另请参阅haskell wiki explanation。
-
Monoid:Monoid 是一种具有零(或空)值的类型,以及一个操作,标记为 <>,它将两个 Monoid 连接在一起,例如 x <> mempty = mempty <> x = x 和 x <> (y <> z) = (x <> y) <> z。这些被称为同一性和关联性定律。许多类型是 Monoid,例如数字,有 mempty = 0 和 <> = +。这在许多情况下都很有用。
-
Arrows:箭头是一种表示接受输入并返回输出的计算的方式。函数是箭头的最基本类型,但还有许多其他类型。该库还有许多用于操作箭头的非常有用的函数 - 即使仅与普通的旧 Haskell 函数一起使用,它们也非常有用。
-
Arrays: Haskell 中的各种可变/不可变数组。
-
ST Monad:允许您编写具有可变状态的代码,该状态运行得非常快,同时在 monad 之外仍然保持纯净。有关详细信息,请参阅链接。
-
FRP:Functional Reactive Programming,一种新的实验性代码编写方式,用于处理事件、触发器、输入和输出(例如 gui)。不过我对此了解不多。 Paul Hudak's talk about yampa 是一个好的开始。
您应该看看许多新的语言功能。我只是列出它们,你可以从谷歌、haskell wikibook、haskellwiki.org 网站和ghc documentation 找到很多关于它们的信息。
- 多参数类型类/功能依赖项
- 类型族
- 存在量化类型
- 幻影类型
- GADTS
- 其他...
很多 Haskell 都是基于 category theory,所以你可能想研究一下。一个好的起点是Category Theory for Computer Scientist。如果不想买书,作者相关article也不错。
最后,您将想要了解有关各种 Haskell 工具的更多信息。其中包括:
-
ghc(及其所有功能)
-
cabal: Haskell 包系统
-
darcs:用 Haskell 编写的分布式版本控制系统,在 Haskell 程序中非常流行。
-
haddock:Haskell 自动文档生成器
在学习所有这些新库和概念的同时,在 Haskell 中编写一个中等规模的项目非常有用。它可以是任何东西(例如小游戏、数据分析器、网站、compiler)。致力于此将使您能够应用您现在正在学习的许多东西。你在这个水平上停留了很多年(这就是我所处的位置)。
专家
你需要几年时间才能达到这个阶段(你好,从 2009 年开始!),但我猜你从这里开始写 phd 论文,新的 ghc 扩展,并提出新的抽象。
获得帮助
最后,在任何学习阶段,都有多个地方可以获取信息。它们是:
- #haskell irc 频道
-
mailing lists。这些都值得注册,只是为了阅读正在进行的讨论 - 有些非常有趣。
- haskell.org 主页上列出的其他地方
结论
结果这比我预期的要长...无论如何,我认为精通 Haskell 是一个非常好的主意。这需要很长时间,但这主要是因为您正在学习一种全新的思维方式。这不像学了 Java 之后学了 Ruby,而是学了 C 之后学了 Java。另外,我发现我的面向对象编程技能由于学习了 Haskell 而得到了提高,因为我看到了许多抽象思想的新方法。