这个问题的答案是 社区的努力。编辑现有答案以改进这篇文章。它目前不接受新的答案或交互。
几天来,我一直试图围绕 Haskell中的函数式编程范式进行思考。我通过阅读教程和观看截屏视频来做到这一点,但似乎没有什么能坚持下去。现在,在学习各种命令式/OO 语言(如 C、Java、PHP)时,练习对我来说是一个很好的方法。但是因为我真的不知道 Haskell有什么能力,而且因为有很多新概念可以利用,所以我不知道从哪里开始。
那么,你是如何学习 Haskell 的呢?是什么让你真正“破冰”?另外,开始练习有什么好主意吗?
我将根据您在 Haskell 中的技能水平来订购本指南,从绝对的初学者到专家。请注意,此过程将花费数月(数年?),因此相当长。
绝对的新人
首先,Haskell 可以做任何事情,并且有足够的技能。它非常快(在我的经验中仅落后于 C 和 C++),并且可以用于从模拟到服务器、gui 和 Web 应用程序的任何事情。
然而,对于 Haskell 初学者来说,有些问题比其他问题更容易编写。数学问题和列表过程程序是很好的候选者,因为它们只需要最基本的 Haskell 知识就可以编写。
学习 Haskell 基础知识的一些很好的指南是Happy Learn Haskell Tutorial和Learn You a Haskell for Great Good(或它的JupyterLab 改编版)的前 6 章。在阅读这些内容时,用你所知道的知识解决简单的问题是一个非常好的主意。
另外两个很好的资源是Haskell Programming from first principle和Programming in Haskell。它们都带有每章的练习,所以你有一些简单的小问题与你在最后几页学到的内容相匹配。
haskell 99 问题页面是一个很好的尝试问题列表。这些从非常基础的开始,随着你的继续变得越来越困难。做很多这些都是很好的练习,因为它们可以让你练习递归和高阶函数的技能。我建议跳过任何需要随机性的问题,因为这在Haskell 中有点困难。如果您想使用 QuickCheck 测试您的解决方案
一旦你完成了其中的一些,你就可以继续做一些ProjectEuler问题。这些是按完成它们的人数排序的,这是一个相当好的难度指示。这些比以前的问题更能测试你的逻辑和Haskell,但你应该仍然能够完成前几个问题。Haskell 解决这些问题的一大优势是整数不受大小限制。要完成其中的一些问题,阅读第 7 章和第 8 章的学习 Haskell 也会很有帮助。
初学者
在那之后,你应该对递归和高阶函数有相当好的处理,所以现在是开始做一些更现实的问题的好时机。一个很好的起点是[Real World Haskell(在线书籍,您也可以购买硬拷贝)。对于以前从未做过函数式编程/使用过递归的人来说,我发现前几章介绍得太快了。但是,通过练习之前的问题,您应该会发现它完全可以理解。
解决本书中的问题是学习如何在 Haskell 中管理抽象和构建可重用组件的好方法。这对于习惯于面向对象(oo)编程的人来说至关重要,因为普通的 oo 抽象方法(oo 类)不会出现在 Haskell 中(Haskell 有类型类,但它们与 oo 类非常不同,更像 oo接口)。我不认为跳过章节是一个好主意,因为每个章节都会引入很多新的想法,这些想法会在后面的章节中使用。
过了一会儿,你会看到第 14 章,可怕的 monads 章节(dum dum dummmm)。几乎每个学习 Haskell 的人都很难理解 monad,因为这个概念非常抽象。我想不出另一种语言中的任何概念与函数式编程中的 monad 一样抽象。Monads 允许将许多想法(例如 IO 操作、可能失败的计算、解析……)统一在一个想法下。因此,如果您在阅读了 monads 章节后并没有真正理解它们,请不要灰心。我发现阅读对 monad 的许多不同解释很有用。每个人都对问题提出了新的看法。这是一个很好的 monad 教程列表。我强烈推荐All About Monads,但其他的也不错。
此外,这些概念需要一段时间才能真正融入其中。这来自于使用,也来自于时间。我发现有时在问题上睡觉比其他任何事情都更有帮助!最终,这个想法会成功,你会想知道为什么你很难理解一个实际上非常简单的概念。当这种情况发生时真是太棒了,当它发生时,你可能会发现 Haskell 是你最喜欢的命令式编程语言 :)
为了确保你完全理解 Haskell 类型系统,你应该尝试解决20 个中级 Haskell 练习。这些练习使用有趣的函数名称,如“furry”和“banana”,可以帮助您很好地理解一些基本的函数式编程概念(如果您还没有这些概念)。用一堆写满箭头、独角兽、香肠和毛茸茸的香蕉的纸来度过一个美好的夜晚。
中间的
一旦你理解了 Monads,我认为你已经从初级 Haskell 程序员转变为中级 Haskeller。那么从这里去哪里呢?我要推荐的第一件事(如果你还没有从学习 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,它将生成大量随机值(在本例中为列表)并测试谓词对于所有结果是否为真。另请参阅在线手册。
length (reverse lst) == length lst
HUnit:Haskell 中的单元测试。
gtk2hs:Haskell 最流行的 gui 框架,让您编写 gtk 应用程序。
happstack:Haskell 的 Web 开发框架。不使用数据库,而是使用数据类型存储。非常好的文档(其他流行的框架是snap和yesod)。
此外,您最终应该学习许多概念(如 Monad 概念)。这将比第一次学习 Monad 更容易,因为您的大脑将习惯于处理所涉及的抽象级别。Typeclassopedia是学习这些高级概念以及它们如何组合在一起的一个很好的概述。
Applicative:类似 Monads 的接口,但功能较弱。每个 Monad 都是 Applicative,但反之则不然。这很有用,因为有些类型是 Applicative 但不是 Monad。此外,使用 Applicative 函数编写的代码通常比使用 Monad 函数编写等效代码更具可组合性。请参阅《学习你的 Haskell 指南》中的Functors、Applicative Functors 和 Monoids。
Foldable , Traversable:抽象了列表的许多操作的类型类,因此可以将相同的功能应用于其他容器类型。另请参阅haskell wiki 说明。
Monoid: Monoid 是一种类型,它具有零(或空)值,以及一个<>将两个 Monoid 连接在一起的操作,例如x <> mempty = mempty <> x = x和x <> (y <> z) = (x <> y) <> z。这些被称为同一性和关联性定律。许多类型是 Monoids,例如数字,带有mempty = 0和<> = +。这在许多情况下都很有用。
<>
x <> mempty = mempty <> x = x
x <> (y <> z) = (x <> y) <> z
mempty = 0
<> = +
箭头:箭头是表示接受输入并返回输出的计算的一种方式。函数是最基本的箭头类型,但还有很多其他类型。该库还具有许多非常有用的用于操作箭头的函数 - 即使仅与普通的旧 Haskell 函数一起使用,它们也非常有用。
数组:Haskell 中的各种可变/不可变数组。
ST Monad:让您编写具有可变状态的代码,运行速度非常快,同时在 monad 之外仍然保持纯净。请参阅链接查看更多细节。
FRP:Functional Reactive Programming,一种新的实验性代码编写方式,用于处理事件、触发器、输入和输出(例如 gui)。不过我对此了解不多。Paul Hudak 关于 yampa 的讨论是一个好的开始。
您应该看看许多新的语言功能。我只会列出它们,你可以从 google、haskell wikibook、haskellwiki.org 站点和ghc 文档中找到很多关于它们的信息。
很多 Haskell都是基于范畴论的,所以你可能想研究一下。\
最后,您将想了解更多有关各种 Haskell 工具的信息。这些包括:
在学习所有这些新库和概念的同时,在 Haskell 中编写一个中等规模的项目非常有用。它可以是任何东西(例如小游戏、数据分析器、网站、编译器)。致力于此将使您能够应用您现在正在学习的许多东西。你在这个水平上停留了很长时间(这就是我所处的位置)。
专家
你需要几年时间才能达到这个阶段(你好,从 2009 年开始!),但我猜你从这里开始写 phd 论文,新的 ghc 扩展,并提出新的抽象。
获得帮助
最后,在学习的任何阶段,都有多个获取信息的地方。这些是:
结论
好吧,结果比我预期的要长…无论如何,我认为精通 Haskell 是一个非常好的主意。这需要很长时间,但这主要是因为您正在学习一种全新的思维方式。这不像学了 Java 之后学了 Ruby,而是学了 C 之后学了 Java。另外,我发现我的面向对象编程技能由于学习了 Haskell 而得到了提高,因为我看到了许多抽象思想的新方法。