我花了几天时间试图理解Haskell中的函数式编程范式。我通过阅读教程和观看屏幕录像来实现这一目标,但似乎没有什么真正的效果。
在学习各种命令式/OO语言(如C、Java、PHP)时,练习是我走过的良好途径。但由于我不知道Haskell能做什么,而且有许多新概念要使用,所以我不知道从哪里开始。
那么,你是如何学习Haskell的?是什么让你真正“打破了僵局”?另外,有什么好的起步练习想法吗?
我花了几天时间试图理解Haskell中的函数式编程范式。我通过阅读教程和观看屏幕录像来实现这一目标,但似乎没有什么真正的效果。
在学习各种命令式/OO语言(如C、Java、PHP)时,练习是我走过的良好途径。但由于我不知道Haskell能做什么,而且有许多新概念要使用,所以我不知道从哪里开始。
那么,你是如何学习Haskell的?是什么让你真正“打破了僵局”?另外,有什么好的起步练习想法吗?
Parsec:用于解析程序和文本。比使用正则表达式更好。文档非常好,还有一个真实世界的Haskell章节。
QuickCheck:非常酷的测试程序。你需要编写一个始终为真的谓词(例如length (reverse lst) == length lst
)。然后将谓词传递给QuickCheck,它将生成许多随机值(在这种情况下是列表)并测试该谓词对所有结果是否为真。也可以参考online manual。
HUnit:Haskell中的单元测试。
gtk2hs:Haskell最流行的GUI框架,可让您编写gtk应用程序。
happstack:用于Haskell的Web开发框架。不使用数据库,而是使用数据类型存储。文档相当不错(其他流行的框架包括snap和yesod)。
Applicative:一种像Monad一样的接口,但不那么强大。每个Monad都是Applicative,但反之则不然。这很有用,因为有些类型是Applicative但不是Monad。此外,使用Applicative函数编写的代码通常比使用Monad函数编写的等效代码更具组合性。请参见Functors,Applicative Functors和Monoids来自learn you a haskell指南。
Foldable,Traversable:抽象了许多列表操作的类型类,以便可以将相同的函数应用于其他容器类型。另请参见haskell wiki explanation。
Monoid:Monoid是一种具有零(或mempty)值和一个操作(表示为<>
)的类型,将两个Monoid连接在一起,使得x <> mempty = mempty <> x = x
和x <>(y <> z)=(x <> y)<> z
。这些被称为标识和结合律。许多类型都是Monoid,例如数字,其中mempty = 0
和<> = +
。这在许多情况下都很有用。
Arrows:箭头是表示输入和输出的计算的一种方式。函数是最基本的箭头类型,但有许多其他类型。该库还具有许多非常有用的用于操作箭头的函数 - 即使仅与普通的Haskell函数一起使用,它们也非常有用。
Arrays:Haskell中各种可变/不可变数组。
ST Monad:允许您编写具有可变状态的代码,而在单子外部保持纯净且运行速度非常快。有关更多详细信息,请参见链接。
FRP:函数响应式编程,一种处理事件,触发器,输入和输出(例如gui)的新型实验性编写代码的方式。我对此了解不多。Paul Hudak's talk about yampa是一个好的开始。
有很多新的语言特性你应该看一下。我会列出它们,你可以从Google、Haskell Wikibook、haskellwiki.org网站和GHC文档中找到关于它们的许多信息。
Haskell 的许多内容都基于范畴论,所以你可能想深入了解一下。一个好的起点是计算机科学家的范畴论。如果你不想买这本书,作者相关的文章也非常好。
最后,你需要了解更多有关 Haskell 工具的知识。这些工具包括:
在学习所有这些新库和概念时,编写一个中等规模的Haskell项目非常有用。它可以是任何东西(例如小游戏、数据分析器、网站、compiler)。在此过程中,您将能够应用许多您正在学习的内容。您会在这个阶段停留很长时间(这就是我所处的阶段)。
专家
到达这个阶段需要几年时间(来自2009年!),但从这里开始,我猜你会开始撰写博士论文、新的ghc扩展,并提出新的抽象概念。
获取帮助
最后,在任何学习阶段,都有多个获取信息的地方。这些是:
结论
嗯,这比我预想的还要长...无论如何,我认为成为 Haskell 熟练者是一个非常好的主意。它需要很长时间,但这主要是因为通过这种方式学习了完全新的思考方式。这不像在学习 Java 后学习 Ruby,而更像在学习 C 后学习 Java。此外,我发现由于学习 Haskell,我的面向对象编程技能也得到了提高,因为我看到了许多抽象思想的新方法。
Monad
更加强大,但组合性更差...很多人在可以使用更简洁的Applicative
代码时使用了Monad
。大多数是Functor
的东西也是Monad
,但如果可以使用fmap
,就不必使用>>=
和return
,因为如果可以使用后者,代码会更简单。 - Tom Crockett我的一些同事在使用《Learn You a Haskell for Great Good!》方面有良好的经验。
该教程旨在帮助那些具有命令式编程语言经验,但以前没有编写过函数式语言程序的人。
另外,您还可以在此处查看答案。
这里有一本不错的书可以在线阅读:Real World Haskell
我所做过的大多数Haskell程序都是为了解决Project Euler问题。
我不久前读到的一条建议是:你应该拥有一套标准的简单问题,你知道如何在理论上解决这些问题,然后每当你尝试学习一种新的语言时,你就用该语言实现这些问题。
我很喜欢观看这个13集的Haskell函数式编程系列。
C9讲座:Erik Meijer博士 - 函数式编程基础: http://channel9.msdn.com/shows/Going+Deep/Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1/
在其他人的答案基础上,还有一个非常有用的工具可以帮助你编写代码(例如解决Project Euler问题):Hoogle。你可以使用命令行界面或Web界面。
在安装了Haskell平台后,请确保运行cabal install hoogle
安装Hoogle。
Hoogle使用示例:
假设你有一个函数f x = 3 * x + 1
,你想将它应用到(5 :: Int)
上,然后再将其应用到结果上,以此类推,并获得这些值的无限列表。你怀疑可能已经存在一个函数来帮助你(虽然不是专门针对你的f
)。
如果这个函数接受f 5
,那么它的类型将为(a -> a) -> a -> [a]
;如果接受5 f
,那么它的类型将为a -> (a -> a) -> [a]
(我们假设该函数适用于通用类型而不仅仅是Int
)。
$ hoogle "a -> (a -> a) -> [a]"
Prelude iterate :: (a -> a) -> a -> [a]
是的,你需要的函数已经存在了,它叫做iterate
。你可以通过使用iterate func 5
来调用它!
相同示例的结果可以在这里找到。
Graham Hutton的《Haskell编程》简洁、相当全面,他多年来教授Haskell的经验确实得以展现。无论你以后去哪里,这几乎总是我推荐给人们开始学习Haskell的东西。
特别是第8章("函数解析器")提供了开始处理monad所需的真正基础,我认为它远远是最好的起点,其次是All About Monads。(关于该章节,请注意网站上的勘误:您不能使用do
形式而不进行一些特殊的帮助。您可能需要先了解类型类并自行解决此问题。)
对于Haskell初学者来说,这很少被强调,但在相当早的时候学习不仅使用monad,而且构建自己的monad也很值得。这并不难,并且自定义的monad可能会使许多任务变得更加简单。
我建议加入#haskell irc频道并在那里提问。这就是我学习Haskell的方式。如果您像上面建议的那样通过《Real World Haskell》进行学习,在这个频道里得到实时问题解答将会非常有帮助。许多聪明的人们在 #haskell 中为了兴趣和利润而编写Haskell,所以你会得到很多好的建议。试试吧!
这是我最喜欢的
Joeri van Eekelen, et al. | Wikibooks
Published in 2012, 597 pages
B. O'Sullivan, J. Goerzen, D. Stewart | OReilly Media, Inc.
Published in 2008, 710 pages
我还可以推荐Yet Another Haskell Tutorial作为入门教程。
另一个非常好的学习资源(可能更适合中级水平),它对我帮助很大,而且在其他答案中似乎没有提到,是Brent Yorgey的Typeclassopedia,它可以在The Monad Reader(第13期)中找到。
它以非常易懂的方式编写,并包含了以下入门建议(除了其他许多内容):
成为专业Haskell开发者智慧的关键有两个:
理解类型。
通过熟悉许多示例,深刻理解每个类型类及其与其他类型类的关系。
The Monad Reader本身就是函数式程序员(不仅仅是Haskell程序员)的绝佳宝藏。