Haskell简介

Haskell是一种纯functional语言。这要先解释函数的side effect,所谓的副作用是指函数在执行过程中处理了一些和函数自身的输出无关的东西。最简单的例子就是在c/c++这类语言中,我们可以访问一个全局变量并修改它(即使所有教科书都不推荐这么做,但c/c++确实可以,有没有能力和去不去做是两回事)。更进一步,任何改变外围状态的动作都属于side effect范畴,如向屏幕输出一行字,读入一个文件等等等等都是有副作用的操作。那么,没有副作用的函数就可以称之为纯函数。或者说,无论在什么情况下,给出相同的参数,返回值都是一样的。

由于这个性质,在写haskell程序时,我们思考的方法需要做彻底的改变。最明显的是,如果有一个变量x(“变量”这个词用在这里不恰当,为了和c比较方便才用),应该说有一个值x,我们不能把它看成一个register,container或任何相似的东西,x就是x,它只是一个名字,我们不能任意的改变它的值。于是,在haskell里不可能出现这样的代码:

int x = 1; x = x+1;

注意,这里x的值被更改了,这种更新叫做destructive update。因为旧的值被新的值代替了。相应的,有这种性质的语言叫做imperative language,c和java都属这一类。(这个性质对思考模式的影响远不止这一点点,下面会说到)

haskell还有一种成为lazy的性质,即一个表达式直到真正被用到的时候才会计算它的值。听上去好像没什么,其实这个性质是很有用的,利用它我们可以表达无限的概念。例如下面的伪码段:

List makeList(){
    List current = new List();
    current.value = 1;
    current.next = makeList();
    return current;
}

很明显的,类似的代码要是拿到java上去跑,就是一个死循环直到栈溢出。拿到代码后立刻计算值的性质叫做strict,反之就是lazy。在haskell中我们可以写这样的代码而不必担心,因为haskell不会去计算它,只是记住makeList这个名字而已。另外,由于递归的概念,haskell的代码更简练:

makeList = 1 : makeList

上面的代码还暗示了我们一样东西,函数没有()。是的,haskell采用的是一种叫layout的系统来减少代码输入量以便使程序看上去更简洁。所以代码中的空格,tab以及缩进都是很重要的。python也采用了相似的系统。

上面说到了haskell没有destructive update。更大的影响就是haskell没有循环。回想一下c里面的循环,无论是for还是while,我们都一定要有一个计数器来决定循环次数或者中止条件吧。但是haskell不能做x=x+1,所以也就不能做传统意义上的循环了。还有什么能让我们重复进行一个动作呢?递归!haskell是递归的世界,所有重复性动作都由递归来实现。这里给个简单的例子,haskell的阶乘:

factorial 1 = 1
factorial n = n * factorial (n-1)

当然,在c里我们也可以写类似的递归,但是c的递归比相应的for循环要慢很多了。

递归也可以用于定于数据结构,比如这是一个二叉树的定义:

data Tree a = Leaf a | Branch (Tree a) (Tree a)

上面式子的意思是一棵树或者是叶子,或者有两个分支,而分支由树来定义。由于数据结构自身的性质,用递归来表达就显得非常优雅。

haskell还有很多高级特性,如多态,类似cpp的STL中的functor等等。且听下回分解

Reference:

[1]. http://www.haskell.org/

[2]. Hal Daume III(2004). Yet Another Haskell Tutorial. http://www.isi.edu/~hdaume/htut/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值