这几天来,我一直在思考Haskell中的函数式编程范例。我通过阅读教程和观看视频来做到这一点,但似乎没有什么能真正坚持下来。 现在,在学习各种命令式/面向对象语言(如C、Java、PHP)时,练习对我来说是一种很好的方式。但是因为我不知道Haskell有什么能力,而且有很多新概念可以利用,所以我不知道从哪里开始。

你是怎么学会哈斯克尔的?是什么让你真正“打破僵局”的?还有,开始练习有什么好主意吗?


当前回答

Graham Hutton的《Programming in Haskell》简明扼要,相当透彻,而且他多年的Haskell教学经验也很好地说明了这一点。这几乎总是我建议人们开始的时候,不管你从哪里开始。

特别是,第8章(“函数解析器”)提供了你需要开始处理单子的真正基础知识,我认为这是目前为止最好的开始,其次是关于单子的所有内容。(不过,关于那一章,请注意网站上的勘误表:如果没有一些特殊帮助,你不能使用do表单。你可能想先了解一下类型类,然后自己解决这个问题。)

Haskell初学者很少会强调这一点,但它值得尽早学习,不仅是使用单子,而且是构造自己的单子。这并不难,定制的可以使许多任务变得更加简单。

其他回答

为了补充别人的答案——有一个有用的答案会在编码时帮助你(例如在解决项目欧拉问题时): Hoogle。可以使用命令行界面,也可以使用web界面。

命令行

在你安装了Haskell平台之后,一定要在cabal上安装hoogle

Hoogle用法示例:

你有一个函数f x = 3 * x + 1,你想把它应用到(5::Int)上,然后把它应用到结果上,然后应用到那个结果上,以此类推,得到一个无限的这些值的列表。你怀疑可能已经存在一个函数来帮助你(虽然不是专门针对你的f)。

该函数的类型为(a -> a) -> a -> [a],如果它的参数为f5;如果它的参数为5f,则为-> (a -> a) -> [a](我们假设该函数适用于一般类型,而不仅仅是int型)

$ hoogle "a -> (a -> a) -> [a]"
Prelude iterate :: (a -> a) -> a -> [a]

是的,你需要的函数已经存在了,它叫做iterate。你可以通过迭代func 5来使用它!

Web界面

可以在这里找到相同示例的结果。

这些是我最喜欢的

Haskell:类型函数式编程

Joeri van Eekelen, et al. | Wikibooks
       Published in 2012, 597 pages

真实世界Haskell

   B. O'Sullivan, J. Goerzen, D. Stewart | OReilly Media, Inc.
   Published in 2008, 710 pages

我很喜欢看这个用Haskell进行函数式编程的13集系列。

C9讲座:Erik Meijer博士-函数式编程基础: http://channel9.msdn.com/shows/Going+Deep/Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1/

我将根据你在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 principles和Programming in Haskell。它们每一章都有练习,所以你有一些小的简单的问题来匹配你在前几页学到的东西。

haskell 99问题页面是一个可以尝试的问题列表。这些练习从最基本的开始,随着练习的进行会变得越来越难。做很多这样的练习是很好的,因为它们可以让你练习递归和高阶函数的技能。我建议跳过任何需要随机性的问题,因为这在Haskell中有点困难。如果你想用QuickCheck测试你的解决方案,请检查这个SO问题(参见下面的Intermediate)。

Once you have done a few of those, you could move on to doing a few of the Project Euler problems. These are sorted by how many people have completed them, which is a fairly good indication of difficulty. These test your logic and Haskell more than the previous problems, but you should still be able to do the first few. A big advantage Haskell has with these problems is Integers aren't limited in size. To complete some of these problems, it will be useful to have read chapters 7 and 8 of learn you a Haskell as well.

初学者

After that you should have a fairly good handle on recursion and higher order functions, so it would be a good time to start doing some more real world problems. A very good place to start is Real World Haskell (online book, you can also purchase a hard copy). I found the first few chapters introduced too much too quickly for someone who has never done functional programming/used recursion before. However with the practice you would have had from doing the previous problems you should find it perfectly understandable.

解决书中的问题是学习如何在Haskell中管理抽象和构建可重用组件的好方法。这对于习惯于面向对象(oo)编程的人来说至关重要,因为正常的oo抽象方法(oo类)不会出现在Haskell中(Haskell有类型类,但它们与oo类非常不同,更像oo接口)。我不认为跳过章节是个好主意,因为每一章都会介绍很多后面章节会用到的新思想。

After a while you will get to chapter 14, the dreaded monads chapter (dum dum dummmm). Almost everyone who learns Haskell has trouble understanding monads, due to how abstract the concept is. I can't think of any concept in another language that is as abstract as monads are in functional programming. Monads allows many ideas (such as IO operations, computations that might fail, parsing,...) to be unified under one idea. So don't feel discouraged if after reading the monads chapter you don't really understand them. I found it useful to read many different explanations of monads; each one gives a new perspective on the problem. Here is a very good list of monad tutorials. I highly recommend the All About Monads, but the others are also good.

此外,要真正理解这些概念也需要一段时间。这来自于使用,也来自于时间。我发现有时候把问题睡一觉比什么都有用!最终,你会明白你为什么要努力去理解一个在现实中非常简单的概念。当这种情况发生时,它是非常棒的,当它发生时,你可能会发现Haskell是你最喜欢的命令式编程语言:)

为了确保你完全理解Haskell类型系统,你应该尝试解决20个中级Haskell练习。这些练习使用了有趣的函数名称,如“furry”和“banana”,如果你还没有掌握一些基本的函数编程概念,可以帮助你很好地理解它们。在一堆写满箭,独角兽,香肠和毛茸茸的香蕉的纸上度过你的夜晚真不错。

中间

Once you understand Monads, I think you have made the transition from a beginner Haskell programmer to an intermediate haskeller. So where to go from here? The first thing I would recommend (if you haven't already learnt them from learning monads) is the various types of monads, such as Reader, Writer and State. Again, Real world Haskell and All about monads gives great coverage of this. To complete your monad training learning about monad transformers is a must. These let you combine different types of Monads (such as a Reader and State monad) into one. This may seem useless to begin with, but after using them for a while you will wonder how you lived without them.

如果你愿意,现在你可以完成现实世界哈斯克尔的书。跳过章节现在真的不重要,只要你有单子下来。选择你感兴趣的就可以了。

有了现在的知识,您应该能够使用cabal上的大多数包(至少是有文档的包……),以及Haskell附带的大多数库。可以尝试的有趣库列表如下:

Parsec: for parsing programs and text. Much better than using regexps. Excellent documentation, also has a real world Haskell chapter. QuickCheck: A very cool testing program. What you do is write a predicate that should always be true (eg length (reverse lst) == length lst). You then pass the predicate the QuickCheck, and it will generate a lot of random values (in this case lists) and test that the predicate is true for all results. See also the online manual. HUnit: Unit testing in Haskell. gtk2hs: The most popular gui framework for Haskell, lets you write gtk applications. happstack: A web development framework for Haskell. Doesn't use databases, instead a data type store. Pretty good docs (other popular frameworks would be snap and yesod).

此外,还有许多概念(如单子概念),你最终应该学习。这将比第一次学习单子更容易,因为你的大脑将习惯于处理所涉及的抽象级别。对于学习这些高级概念以及它们是如何组合在一起的,有一个很好的概述,那就是类型化类百科全书。

Applicative: An interface like Monads, but less powerful. Every Monad is Applicative, but not vice versa. This is useful as there are some types that are Applicative but are not Monads. Also, code written using the Applicative functions is often more composable than writing the equivalent code using the Monad functions. See Functors, Applicative Functors and Monoids from the learn you a haskell guide. Foldable,Traversable: Typeclasses that abstract many of the operations of lists, so that the same functions can be applied to other container types. See also the haskell wiki explanation. Monoid: A Monoid is a type that has a zero (or mempty) value, and an operation, notated <> that joins two Monoids together, such that x <> mempty = mempty <> x = x and x <> (y <> z) = (x <> y) <> z. These are called identity and associativity laws. Many types are Monoids, such as numbers, with mempty = 0 and <> = +. This is useful in many situations. Arrows: Arrows are a way of representing computations that take an input and return an output. A function is the most basic type of arrow, but there are many other types. The library also has many very useful functions for manipulating arrows - they are very useful even if only used with plain old Haskell functions. Arrays: the various mutable/immutable arrays in Haskell. ST Monad: lets you write code with a mutable state that runs very quickly, while still remaining pure outside the monad. See the link for more details. FRP: Functional Reactive Programming, a new, experimental way of writing code that handles events, triggers, inputs and outputs (such as a gui). I don't know much about this though. Paul Hudak's talk about yampa is a good start.

有很多新的语言特性你应该看一看。我会列出它们,你可以从谷歌,haskell wikibook, haskellwiki.org网站和ghc文档中找到很多关于它们的信息。

多参数类型类/函数依赖关系 类型的家庭 存在量化的类型 幻类型 GADTS 其他人……

Haskell的很多内容都是基于范畴理论的,所以您可能需要研究一下。一个好的起点是《计算机科学家的范畴理论》。如果你不想买这本书,作者的相关文章也很不错。

最后,您将希望更多地了解各种Haskell工具。这些包括:

GHC(及其所有功能) cabal: Haskell包系统 darcs:一个用Haskell编写的分布式版本控制系统,在Haskell程序中非常流行。 hadock:一个Haskell自动文档生成器

在学习所有这些新库和概念的同时,用Haskell编写一个中等规模的项目是非常有用的。它可以是任何东西(如小游戏、数据分析、网站、编译器)。这样做可以让你应用你正在学习的很多东西。你会在这个水平上停留很长时间(这就是我所处的位置)。

专家

你将花费数年时间到达这个阶段(从2009年开始!),但我猜你从这里开始写博士论文,新的ghc扩展,并提出新的抽象概念。

得到帮助

最后,在学习的任何阶段,都有多个获取信息的地方。这些都是:

#haskell irc频道 邮件列表。仅仅为了阅读其中的讨论就值得报名参加——有些非常有趣。 haskell.org主页上列出的其他地方

结论

结果比我预期的要长……无论如何,我认为精通Haskell是一个非常好的主意。这需要很长时间,但这主要是因为你正在通过这样做学习一种全新的思维方式。这并不像在学习Java之后学习Ruby,而是像在学习c之后学习Java。而且,我发现我的面向对象编程技能因为学习Haskell而得到了提高,因为我看到了许多抽象思想的新方法。

不要试图用有趣的隐喻去阅读所有的单子教程。他们只会把你弄得更糟。