1. Haskell介绍
什么是Haskell?
Haskell是一种纯函数式编程语言,在命令式语言中,通过向计算机提供一系列任务然后执行这些任务来完成任务。在执行时,可以改变状态,比如将变量a设置为5,然后执行一些操作,将其设置为其他的值。可以使用控制流结构来多次执行某些操作。在纯函数式编程中,您不会告诉计算机要做什么,而是告诉它事物是什么。一个数字的阶乘是从1到该数字的所有数字的乘积,一组数字的总和是第一个数字加上其他所有数字的总和,依此类推。您将这些信息表示为函数。此外,您不能将变量设置为某个值,然后以后再将其设置为其他值。如果您说a等于5,您不能后来说它是其他值,因为您刚刚说它是5。所以在纯函数式语言中,函数没有副作用。函数唯一能做的事情就是计算某些内容并将其作为结果返回。起初,这似乎有点限制,但实际上它有一些非常好的后果:如果一个函数使用相同的参数调用两次,它保证返回相同的结果。这被称为引用透明性,它不仅允许编译器推断程序的行为,还允许您轻松地推断(甚至证明)一个函数是正确的,然后通过将简单函数组合在一起构建更复杂的函数。
Haskell is lazy,除非另有说明,否则Haskell不会执行函数并计算东西,直到它被强制显示结果。这与引用透明度相得益彰,允许将程序视为对数据的一系列转换。它还有一些很酷的地方,例如无限数据结构。假设有一个不可变的数字列表xs = [1,2,3,4,5,6,7,8]和一个函数doubleMe,它将每一个元素乘以2,然后返回一个新的列表。如果我们想用命令式语言将列表乘以8并执行doubleMe(doubleMe(doubleMe(xs))),他可能会遍历列表一次并制作副本,然后返回。然后它会再遍历该列表两次并返回结果。在惰性语言中,在列表调用doubleMe而不强制显示结果的话,程序会告诉您“是的,我稍后会做”。但是一旦你想看到结果,第一个doubleMe告诉第二个他想要结果,现在第二个向第三个说,第三个不情愿地返回一个双倍的1,即2。第二个接受到该值并将4返回给第一个,第一个看到返回的结果并告诉您8,因此,只有在真正需要的时候才遍历列表。这样,当您想要从惰性语言中获得某些东西时,只需要获取一些初始数据并有效转化和修补,使其类似与您最终想要的东西。
Haskell是静态类型的。当编译程序时,编译器知道哪段代码是数字,哪段代码是字符串等。这意味着在编译时会捕获很多困难的错误。如果尝试将数字和字符串相加,编译器会向您抱怨。Haskell使用了一个非常好的类型系统,具有类型推断功能。这意味着我们不需要用类型显式标记每段代码,因为类型系统可以智能计算出很多相关的信息。如果我们说a = 5 + 4,不必告诉Haskell a是一个数字,它可以自己计算出来。类型推断可以让代码更通用。如果您创建的函数接受两个参数并将它们加在一起,并且您没有明确声明类型,则该函数将任意处理两个像数字一样的参数。
Haskell优雅而简洁,由于Haskell使用了大量高级的概念,因此通常比其命令式程序更短,较短的程序比较长的程序更容易维护,并且错误更少。
深入了解
我们将使用GHC,这是最广泛使用的Haskell编译器。GHC可以采用Haskell脚本(通常有.hs扩展名)并对其进行编译,但它还有交互模式。允许我们与脚本进行交互。我们可以从加载的脚本中调用函数,结果会立即显示。对于学习来说,这比每次进行更改时都进行编译然后从提示符下运行程序要容易很多,速度也快很多。通过在提示符下输入gchi来调用交互模式。如果在名为myfunctions.hs的文件中定义了一些函数,则可以通过键入:l myfunctions来加载这些函数,然后可以使用它们,前提是myfunctions.hs与gchi位于同一文件夹中被调用。如果更改.hs脚本,只需再次运行:l myfunction或者执行:r,这是等效的,因为它会重新加载当前的脚本。我们要做的一般就是在.hs中定义一些函数,加载并摆弄它们。然后更改.hs文件,再次加载等等。