Haskell学习笔记<二>

…第四章 函数的语法

Let it be

    let绑定类似于where绑定,都是用来定义局部变量(函数),其语法结构是:

let [bindings] in [expressions]

    let绑定与where的区别之处在于,前者是一个表达式,而后者却是一个语法结构。表达式是可以嵌入其他表达式的,前面学到的if语句也是一种表达式。如果定义的局部变量不止一个,可以写在一行用";"隔开,也可以断行对齐。遵从list comprehension的语法结构,let表达式绑定的名字在输出函数及限制条件中均可见。由于let…in的限制范围很小,所以需要与作用域更大的where配合使用。

case表达式

    模式匹配其实只是case表达式的语法糖,case语句的结构是:

case [expression] of [pattern] -> [result]

         [pattern]->[result]

    case语句也是一种表达式,因此它可以用在模式匹配无法使用的地方。通过与if…else的灵活配合来使代码更加简洁。

第五章 递归

    我们知道,在命令式语言中,知道一个算法,把它转化成代码,并非一蹴而就的。因为命令式语言强调"步骤",比如quick-sort,其伪代码(CLRS)是:

  1. quick_sort(A,p,r)
  2. if p<r
  3.     then q<-Partition(A,p,r)
  4.         quick_sort(A,p,q-1)
  5.         quick_sort(A,q+1,r)
  6. Partition(A,p,r)
  7. x<-A[r]
  8. i<-p-1
  9.     for j<-p to r-1
  10.         do if A[j]<=x
  11.         then i=i+1
  12.             swap A[i]<->A[j]
  13. return i+1

    但是如果我们用语言描述它,其实很简单:选出主元,将比主元小的快排到主元左边,比主元大的快排到主元右边。也就是说:语言的抽象能力大于代码。我们知道Haskell的特点就是高级抽象,虽然不能够比语言更抽象,但是在很多情况下能够很直白的将算法描述翻译成代码。对于quick-sort,Haskell的描述就很简洁:

  1. quick_sort::(Ord a)=>[a]->[a]
  2. quick_sort []=[]
  3. quick_sort (x:xs)=quick_sort [small | small<-xs,small<=x] ++ [x] ++ quick_sort [big | big<-xs,big>x]

    对于haskell而言,大部分程序需要我们"递归式"思考,这也是FP与CP最大的区别之处。更抽象、更简洁,但是效率上就就依赖于语言自身(或编译器)。

    本章其他的例程主要列举了list相关的一些常用算法的hs实现,这些算法的思路大致相似,都是利用递归实现。首先找到边界条件,然后思考任意子list的递归关系。这种思路被称为"折叠"。

第六章 高阶函数

    从本章开始,教材的节奏加快,开始介绍Haskell的核心特性。

柯里函数

    这名字蛮怪的,单词是Curried functions,直译是"加了咖啡的函数"( ̄▽ ̄") 。下面简称为CF吧…CF是Haskell的重要特性。CF的主要含义:所有函数都可以拆分成只含有一个参数的函数,如果以不完全的方式调用某个函数,就可以得到一个新的函数。说起来很绕,其实放在数学中是很容易理解的:

    上式是一个三元函数,这里的x,y,z就相当于haskell中的函数参数。假设我们令

    g(t)就是一个新的函数,它是f(x,y,z)的不完全调用。Haskell的有类似于此的特性,换句话说,Haskell中的函数与数学中的函数具有一定的行为一致性而与命令式语言中的函数差别较大。具体的语法结构上,有些细节需要注意:

    部分调用必须是前x个参数,不能跳跃(这和C++中默认实参不能跳跃的原因类似)。不过后缀函数和中缀函数可以通过` `或()相互转换,所以通过适当的调整总是可以构造出想要的函数的,比如 div x y为x/y,在此基础上构造任意数3的函数,可以表达为:divThree=(`div` 3),这样divThree x=(`div` 3) x= x `div` 3 = div x 3,目的达到。唯一的例外是(-x),这里不再表示中缀函数,只是普通的负数。

    高阶函数的概念与CF一脉相承,也是来源于数学。我们知道是一个复合函数,如果一个函数中调用了其他函数,称之为高阶函数。如果C语言形参中有函数指针,可以完成回调函数的功能。Haskell中高阶函数可以完成的事情要复杂的多——事实上Haskell的大部分功能都是用高阶函数实现的,没有循环语句,没有赋值语句,这些在命令式语句中必不可少的东西都被高阶函数代替。

to be continued…

原文地址:https://www.cnblogs.com/livewithnorest/p/2600413.html