Haskell初学指南(一)

本文是Haskell初学者系列的第一篇,介绍了Haskell的基本概念,包括交互式环境、类型系统、函数和Main函数。通过实例展示了如何在GHCI中使用Haskell,以及如何进行简单的函数重构和代码编译。
摘要由CSDN通过智能技术生成

这是面向初学者的函数式语言 Haskell 系列的第一篇1


我使用Python已经有十年了,在编写Python时,我总是倾向于以“函数式”方式编写代码 - mapfilterlambda等等,这让我感到整洁和快乐。遵循这种温暖的感觉,我决定尝试一种真正的函数式语言。

所以我在网上阅读了一些教程,并阅读了著名的Learn You a Haskell for Great Good!这是一段漫长而痛苦的旅程——还没有结束。回顾一番之后,我想根据我的 Python 经验分享我自己对 Haskell 的理解。

什么是 Haskell

根据维基百科:

Haskell ( /ˈhæskəl/ [27] ) 是一种通用的静态类型的纯函数式 编程语言,具有类型推断惰性求值。[28] [29] Haskell 为教学、研究和工业应用而设计,开创了许多高级编程语言功能,例如类型类,这些功能支持类型安全的运算符重载

很多非常花哨的词,希望这不会是你通往启蒙的道路上的障碍。

可以在此处找到安装指南:https : //www.haskell.org/platform/,根据你自己的操作系统选择安装。

交互式环境

就像大多数编程语言一样,Haskell 也有一个交互式环境,可以通过在终端输入以下内容打开: ghci

让我们试一下:

~ ghci
GHCi, version 8.10.5: https://www.haskell.org/ghc/  :? for help
Prelude> a = 4
Prelude> b = 6
Prelude> c = a + b
Prelude> c
10

这里没什么值得惊讶的,Haskell 拥有您可以想象的所有基本数据类型:Boolean、Num、Char(用单引号括起来的字符)、String(用双引号括起来的任意数量的字符)等等。

Types

GHCI 中有一个有用的命令,:t将返回输入内容的类型:

Prelude> :t 'a'
'a' :: Char
Prelude> :t "abcd"
"abcd" :: [Char]

我们可以看到它'a'是 Char 类型的,而"abcd"的类型为[Char],一个 Char类型的列表。Char列表等于字符串?让我们检查一下是否属实。

我们将使用列表来验证它:

Prelude> let a = ['a', 'b', 'c']
Prelude> :t a
a :: [Char]
Prelude> let b = "abc"
Prelude> :t b
b :: [Char]

好吧,同样的类型,很好。但真的一样吗?

Prelude> a == b
True

确实一样。

Functions

现在你可以在文件中编写Haskell 代码了。 打开一个文件并将其命名为 fn.hs,文件最好在已启动的ghci所在目录,否则我建议您CTRL+D,结束当前ghci,并在文件所在目录启动新的ghci

我们将编写以下内容:

powerOfTwo x = x ** 2

然后,您可以通过ghci运行以下命令加载您的脚本,而不是编译并运行它(稍后将介绍):

Prelude> :l fn.hs
[1 of 1] Compiling Main             ( fn.hs, interpreted )
Ok, one module loaded.

如您所见,我们的文件 fn.hs已加载到环境中,我们现在可以使用它:

*Main> powerOfTwo 4
16.0
*Main> powerOfTwo 5
25.0
*Main> powerOfTwo 6
36.0

看起来挺好的。现在计算 3 的幂的函数怎么样?让我们编辑我们的文件 fn.hs

powerOfTwo x = x ** 2

powerOfThree x = x ** 3

然后我们可以很方便的重新加载它:

*Main> :r
[1 of 1] Compiling Main             ( fn.hs, interpreted )
Ok, one module loaded.

请注意,ghci有自动补全的功能,输入power,然后按TAB键,将会列出所有power开头的函数。让我们试试我们的powerOfThree函数:

*Main> powerOfThree 2
8.0
*Main> powerOfThree 23
12167.0
*Main> powerOfThree 4
64.0

看起来挺好的。但是现在,如何进行一些重构,只需要一个函数就可以计算 x 的 y 次幂?这样,当新要求说我们需要 7 和 42 的幂时,您不需要写重复代码。它应该是这样的:

powerOfTwo x = x ** 2

powerOfThree x = x ** 3

powerOfX x y = x ** y

然后像往常一样测试我们的代码:

*Main> :r
[1 of 1] Compiling Main             ( fn.hs, interpreted )
Ok, one module loaded.
*Main> powerOf
powerOfThree  powerOfTwo    powerOfX
*Main> powerOfX 2 3
8.0
*Main> powerOfX 2 2
4.0
*Main> powerOfX 2 7
128.0
*Main> powerOfX 7 2
49.0

奇妙吧,我们重新加载了我们的脚本,保留了我们之前的函数(在第二行输入powerof后按TAB),并且能够使用我们的带两个参数新函数。

现在假设我们的函数powerOfTwopowerOfThree在整个代码库中被调用了 1,000 次,并且很难将它们全部替换为powerOfx. 但我们仍然想重构它。我们可以执行以下操作:

powerOfTwo x = powerOfX x 2

powerOfThree x = powerOfX x 3

powerOfX x y = x ** y

你会注意到这里的顺序并不重要,你仍然可以在后面声明powerOfX,即使它会在更前面的地方使用到。

Main

现在,你不想再在ghci中编写Haskell了,你想把文件编译成二进制的可执行文件。

你需要这样做:

powerOfTwo x = powerOfX x 2 
powerOfThree x = powerOfX x 3 
powerOfX x y = x ** y

main = do
    putStrLn "Let's calculate some power !"
    print (powerOfX 2 2)

这里有几件事需要说明:

  • 如果你想运行一个程序,你需要从main = do这个概念开始,这跟许多其他的编程语言类似。我们将在讨论 I/O 后详细回顾这一点。
  • putStrLn 是您常用的函数,在标准输出中输出一个字符串,然后换行。
  • 当我们调用powerOfX时,使用了print函数,它与putStrLn的区别是没有换行。但重点是括号,在Haskell中没有针对函数调用的特定语法。之前我们简单地使用空格来分隔我们的参数,但在这里,我们在print之后调用了powerOfX,因此我们需要使用括号来解释参数属于哪个函数。另一种方法是使用$
print $ powerOfX 2 2

更多的解释会在接下来的文章中给出,因为它涉及到各种概念,比如柯里化。

最后,我们可以像这样编译和调用我们的程序:

$ ghc --make fn.hs
[1 of 1] Compiling Main             ( fn.hs, fn.o )
Linking fn ...
$ ./fn            
Let's calculate some power !
4.0

请注意,您可以使用许多不同的ghc编译选项,更多详细信息可以在他们的文档中找到。

结论

我希望这不会太难,尽管我知道你们中的一些人在后面睡着了。在下一篇文章中,我们将讨论函数定义(我们只看实现)和列表,并与 Python 的代码进行一些比较。


  1. 本文翻译自Haskell series part 1 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值