Haskell 入门

2024-05-15

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

那么,你是如何学习 Haskell 的呢?是什么让你真正“破冰”?另外,对于开始练习有什么好的想法吗?


我将根据您在 Haskell 中的技能水平来订购本指南,从绝对的初学者到专家。请注意,这个过程将花费数月(数年?),因此相当长。

绝对的新人

首先,Haskell 具备足够的技能,可以做任何事。它速度非常快(根据我的经验,仅落后于 C 和 C++),并且可用于从模拟到服务器、GUI 和 Web 应用程序的任何内容。

然而,对于 Haskell 初学者来说,有些问题比其他问题更容易编写。数学问题和列表处理程序是很好的选择,因为它们只需要最基本的 Haskell 知识就可以编写。

学习 Haskell 基础知识的一些很好的指南是快乐学习Haskell教程 http://www.happylearnhaskelltutorial.com以及前 6 章为你学习 Haskell 以获得伟大的好处 http://learnyouahaskell.com/(或其JupyterLab 适配 https://github.com/jamesdbrock/learn-you-a-haskell-notebook)。在阅读这些内容时,最好也用您所知道的知识来解决简单的问题。

另外两个好资源是Haskell 编程从第一原理开始 http://haskellbook.com/, and Haskell 编程 http://www.cs.nott.ac.uk/%7Epszgmh/pih.html。它们每章都配有练习,因此您会遇到与您在最后几页学到的内容相匹配的小简单问题。

一个很好的尝试问题列表是Haskell 99 问题页面 https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems。这些一开始非常基础,随着你的继续,会变得越来越困难。做很多这样的事情是非常好的练习,因为它们可以让你练习递归和高阶函数的技能。我建议跳过任何需要随机性的问题,因为这在 Haskell 中有点困难。查看这个问题 https://stackoverflow.com/questions/5683911/simple-haskell-unit-testing如果您想使用 QuickCheck 测试您的解决方案(请参阅中间的 below).

一旦你完成了其中的一些,你就可以继续做一些欧拉计划 http://projecteuler.net/index.php?section=problems问题。这些是按照完成人数排序的,这很好地表明了难度。这些问题比前面的问题更考验你的逻辑和 Haskell,但你仍然应该能够完成前几个问题。 Haskell 解决这些问题的一大优势是整数的大小不受限制。为了解决其中一些问题,阅读《学习 Haskell》的第 7 章和第 8 章也会很有用。

Beginner

之后,您应该对递归和高阶函数有相当好的掌握,因此这是开始解决一些更现实世界问题的好时机。一个很好的起点是现实世界哈斯克尔 http://book.realworldhaskell.org/(在线书籍,您也可以购买纸质版)。我发现对于以前从未做过函数式编程/使用过递归的人来说,前几章介绍得太多太快了。然而,通过前面的问题的练习,你应该会发现它完全可以理解。

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

过了一会儿,您将到达第 14 章,即可怕的 monads 章节 (dum dum dummmm)。几乎每个学习 Haskell 的人都很难理解 monad,因为这个概念非常抽象。我想不出另一种语言中有任何概念像函数式编程中的 monad 一样抽象。 Monads 允许将许多想法(例如 IO 操作、可能失败的计算、解析……)统一到一个想法下。因此,如果在阅读 monad 章节后您还没有真正理解它们,请不要感到沮丧。我发现阅读对单子的许多不同解释很有用;每个人都对问题提出了新的视角。这里有一个非常好的Monad 教程列表 https://wiki.haskell.org/Tutorials#Using_monads。我强烈推荐关于 Monad 的一切 https://wiki.haskell.org/All_About_Monads,不过其他的也都不错。

此外,这些概念需要一段时间才能真正被理解。这是通过使用来实现的,但也通过时间来实现。我发现有时候解决问题比睡觉更有帮助!最终,这个想法会被采纳,你会想知道为什么你很难理解一个实际上非常简单的概念。当这种情况发生时真是太棒了,当它发生时,你可能会发现 Haskell 成为你最喜欢的命令式编程语言:)

为了确保您完全理解 Haskell 类型系统,您应该尝试解决20 个中级 Haskell 练习 http://blog.tmorris.net/posts/20-intermediate-haskell-exercises/。这些练习使用有趣的函数名称,如“furry”和“banana”,可以帮助您很好地理解一些基本的函数式编程概念(如果您还没有这些概念)。与一堆贴满箭头、独角兽、香肠和毛茸茸的香蕉的文件一起度过一个美好的夜晚。

中间的

一旦你理解了 Monads,我认为你已经从初级 Haskell 程序员过渡到中级 Haskell 了。那么接下来该去哪里呢?我首先推荐的(如果您还没有通过学习 monad 来学习它们)是各种类型的 monad,例如 Reader、Writer 和 State。再次,Real world Haskell 和 All about monads 对此进行了很好的报道。要完成 monad 培训,必须学习 monad 转换器。这些使您可以将不同类型的 Monad(例如 Reader 和 State monad)组合为一。一开始这似乎没什么用,但使用一段时间后,你会想知道没有它们你是如何生活的。

现在,如果您愿意,您可以完成现实世界的 Haskell 书。现在跳过章节并不重要,只要你掌握了单子。只需选择您感兴趣的内容即可。

凭借您现在掌握的知识,您应该能够使用 cabal 上的大多数软件包(至少是有文档记录的软件包......),以及 Haskell 附带的大多数库。值得尝试的有趣库列表如下:

  • Parsec https://wiki.haskell.org/Parsec:用于解析程序和文本。比使用正则表达式好得多。优秀的文档,还有现实世界的 Haskell 章节。

  • 快速检查 http://www.cse.chalmers.se/%7Erjmh/QuickCheck/:一个非常酷的测试程序。你所做的就是编写一个应该始终为真的谓词(例如length (reverse lst) == length lst)。然后,您将谓词传递给 QuickCheck,它将生成许多随机值(在本例中为列表)并测试谓词对于所有结果是否都为真。另请参阅在线手册 http://www.cse.chalmers.se/%7Erjmh/QuickCheck/manual.html.

  • HUnit http://hunit.sourceforge.net/:Haskell 中的单元测试。

  • gtk2hs http://projects.haskell.org/gtk2hs/:Haskell 最流行的 GUI 框架,可让您编写 gtk 应用程序。

  • 快乐栈 http://happstack.com/:Haskell 的 Web 开发框架。不使用数据库,而是使用数据类型存储。非常好的文档(其他流行的框架是snap http://snapframework.com/ and yesod http://www.yesodweb.com/).

此外,还有许多您最终应该学习的概念(例如 Monad 概念)。这比第一次学习 Monad 更容易,因为你的大脑将习惯于处理所涉及的抽象级别。学习这些高级概念以及它们如何组合在一起的一个很好的概述是类型分类百科全书 http://www.haskell.org/haskellwiki/Typeclassopedia.

  • Applicative:类似于 Monad 的接口,但功能较弱。每个 Monad 都是适用的,但反之则不然。这很有用,因为有些类型是 Applicative 但不是 Monad。此外,使用 Applicative 函数编写的代码通常比使用 Monad 函数编写等效代码更具可组合性。看函子、应用函子和幺半群 http://learnyouahaskell.com/functors-applicative-functors-and-monoids#functors-redux来自《学习 Haskell 指南》。

  • Foldable http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Foldable.html,可穿越 http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Traversable.html:类型类抽象了列表的许多操作,以便相同的功能可以应用于其他容器类型。另请参阅Haskell 维基解释 https://wiki.haskell.org/Foldable_and_Traversable.

  • Monoid https://wiki.haskell.org/Monoid:Monoid 是一种具有零(或空)值和一个操作的类型,用符号表示<>将两个幺半群连接在一起,这样x <> mempty = mempty <> x = x and x <> (y <> z) = (x <> y) <> z。这些称为恒等律和结合律。许多类型都是幺半群,例如数字,mempty = 0 and <> = +。这在很多情况下都很有用。

  • Arrows http://www.haskell.org/arrows/:箭头是一种表示接受输入并返回输出的计算的方式。函数是最基本的箭头类型,但还有许多其他类型。该库还有许多非常有用的操作箭头的函数 - 即使仅与普通的旧 Haskell 函数一起使用,它们也非常有用。

  • Arrays https://wiki.haskell.org/Modern_array_libraries:Haskell 中的各种可变/不可变数组。

  • ST Monad https://wiki.haskell.org/Monad/ST:让您可以编写运行速度非常快的可变状态代码,同时在 monad 之外仍然保持纯净。请参阅链接查看更多细节。

  • FRP:函数响应式编程,一种新的、实验性的编写处理事件、触发器、输入和输出(例如 GUI)的代码的方法。不过我对此了解不多。Paul Hudak 谈论 yampa http://vimeo.com/96744621是一个好的开始。

您应该了解许多新的语言功能。我只是列出它们,你可以从谷歌找到很多关于它们的信息,哈斯克尔维基百科 http://en.wikibooks.org/wiki/Haskell、haskellwiki.org 网站和GHC 文档 https://wiki.haskell.org/GHC.

  • 多参数类型类/函数依赖
  • 类型家族
  • 存在量化类型
  • 幻影类型
  • GADTS
  • 其他的...

Haskell 的很多内容都是基于范畴论 http://en.wikipedia.org/wiki/Category_theory,所以你可能想研究一下。一个好的起点是计算机科学家范畴论 https://rads.stackoverflow.com/amzn/click/com/0262660717。如果你不想买这本书,作者的相关也很优秀。

最后,您将想要了解有关各种 Haskell 工具的更多信息。这些包括:

  • ghc https://wiki.haskell.org/GHC(及其所有功能)
  • cabal http://www.haskell.org/cabal/:Haskell 包系统
  • darcs http://darcs.net/:用 Haskell 编写的分布式版本控制系统,在 Haskell 程序中非常流行。
  • haddock http://www.haskell.org/haddock/:Haskell 自动文档生成器

在学习所有这些新库和概念的同时,用 Haskell 编写一个中等规模的项目非常有用。它可以是任何东西(例如小游戏、数据分析器、网站、compiler http://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours)。致力于此将使您能够应用您现在正在学习的许多内容。你会在这个水平上停留很长时间(这就是我所处的位置)。

Expert

你需要几年的时间才能到达这个阶段(2009 年你好!),但从这里我猜你开始撰写博士论文、新的 ghc 扩展,并提出新的抽象。

寻求帮助

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

  • #haskell irc 频道
  • the 邮件列表 https://wiki.haskell.org/Mailing_lists。这些内容值得注册,只是为了阅读其中的讨论 - 有些非常有趣。
  • haskell.org 主页上列出的其他地点

结论

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell 入门 的相关文章

  • 如何使用foldr为列表创建显示实例?

    我想为我的数据类型 我的列表 编写自己的显示实例 到目前为止 我的方法是有效的 但我总是在末尾有一个逗号 我已经尝试用最后一个元素启动折叠并将其从列表中删除 但它很麻烦而且不起作用 有没有更简单的方法来获得正确的解决方案 实际 1 2 3
  • 为什么 mod 在表达式中给出的结果与在函数调用中给出的结果不同?

    假设有人想要计算函数 f x y x mod 3 y mod 3 mod 2 那么 如果再展开f 1 0 手动 可以得到 1 mod 3 0 mod 3 mod 2 1 然而 如果使用内联函数 结果是 let f x y x mod 3 y
  • Scala 函数定义参数列表中不同的括号样式

    Scala 中以下两个函数定义有什么区别 1 def sum f Int gt Int a Int b Int Int code 2 def sum f Int gt Int a Int b Int Int code SBT 的控制台 RE
  • F# 静态成员类型约束

    我正在尝试定义一个函数 factorize 它使用类似于 Seq sum 的结构类型约束 需要静态成员 Zero One 和 以便它可以与 int long bigint 等一起使用 似乎无法获得正确的语法 并且无法找到有关该主题的大量资源
  • 如何让 do 块提前返回?

    我正在尝试使用 Haskell 抓取网页并将结果编译到一个对象中 如果出于某种原因 我无法从页面获取所有项目 我想停止尝试处理页面并提前返回 例如 scrapePage String gt IO scrapePage url do doc
  • Haskell Fibonacci 达到最大指定数?

    我有一个已启动并正在运行的 Haskell 函数 但它做错了事情 它应该输出最多指定最大数量的斐波那契数列 像这样 fibonacciSequence 86 1 1 2 3 5 8 13 21 33 54 我的代码当前输出斐波那契数列中的前
  • 忽略 Racket 中的多个返回值

    在 Racket 中 可以通过执行以下操作从函数返回多个值 define foo values 1 2 3 然后我们可以通过这样做来绑定它们 define values one two three foo Now one一定会1 two t
  • 对列表中的相邻元素进行分组

    假设我想编写一个函数来执行此操作 输入 1 1 3 3 4 2 2 5 6 6 输出 1 1 3 3 4 2 2 5 6 6 它将相同的相邻元素分组 这个方法的名称应该是什么 此操作有标准名称吗 In 1 1 3 3 4 2 2 5 6 6
  • Haskell 中多核编程的现状如何?

    Haskell 中多核编程的现状如何 现在有哪些项目 工具和库可用 有哪些经验报道 2009年至2012年期间 发生了以下事件 2012 从 2012 年开始 并行 Haskell 状态更新开始出现在并行 Haskell 摘要 http w
  • 如何在 Octave 中使用具有自定义功能的地图?

    假设我有一个集合A A 0 6 100 我有一个功能fib n function retval fib n g1 1 5 5 2 g2 1 5 5 2 retval 1 5 5 g1 n g2 n endfunction 我希望能够申请fi
  • 相当于 Java 中 C++ 的 std::bind 吗?

    有没有一种方法可以像 C 中的 std bind 一样将 Java 中的参数绑定到函数指针 Java 中类似的东西会是什么 void PrintStringInt const char s int n std cout lt lt s lt
  • 如何与更高级别的类型合作

    玩弄教堂的数字 我遇到了无法指导 GHC 类型检查器处理高阶类型的情况 首先我写了一个版本 没有任何类型签名 module ChurchStripped where zero z z inc n z s s n z s natInteger
  • 哪种编程语言或库可以处理无限级数?

    哪种编程语言或库能够处理无限级数 例如几何级数或调和级数 它可能必须有一些众所周知的系列的数据库 并在收敛的情况下自动给出适当的值 并且可能在发散的情况下生成异常 例如 在 Python 中 它可能如下所示 sum 0 sign 1 0 f
  • 不同类型的列表?

    data Plane Plane point Point normal Vector Double data Sphere Sphere center Point radius Double class Shape s where inte
  • IntSummaryStatistics的summaryStatistics方法

    为什么空 IntStream 上的 summaryStatistics 方法返回整数的最大和最小值作为流中存在的最大和最小 int 值 IntStream intStream IntStream of IntSummaryStatistic
  • Cabal:使用源代码构建目录

    我有一个src目录 在这个目录中我有Main hs文件和Test目录 在里面Test我有的目录Test hs模块 我需要用 cabal 来编译它 在我的阴谋集团文件中 我有 Executable main hs or lhs file co
  • 承诺的反面是什么?

    承诺代表将来可能可用 或无法实现 的值 我正在寻找的是一种数据类型 它表示将来可能变得不可用的可用值 可能是由于错误 Promise a b TransitionFromTo
  • 需要澄清令人困惑的 Http4s 消息类型 `Response[F]` / `Request[F]`

    我很难理解为什么Request and Response参数化为F 类似的东西是猫效应数据类型资源 从文档中 https typelevel org cats effect docs std resource https typelevel
  • Haskell if-then-else 条件中的“解析输入错误”

    当我尝试编译以下 do 块时 它会抛出错误 输入 conn 上的解析错误 我尝试了许多不同的 if then else 语句配置 但均无济于事 在我添加条件之前 数据库逻辑就起作用了 所以这没有问题 else 中是否有太多行 有没有办法在不
  • Haskell 五个独特的 Wordle 单词

    为了好玩 我正在尝试解决 Matt Parker 在他的 Haskell 频道 Standup Maths in Haskell 频道的链接视频中谈到的与 Wordle 相关的问题 基本上 找到 5 个没有任何共同字母的 5 个字母单词 因

随机推荐