June 8, 2007

Haskell:函数 or 数据

haskell里面是不是所有的函数都是lambda实现的?不然为什么 :t 操作符所返回的都是 lambda的表示,也就是说都是用lambda解释的.
呵呵,最好讲下haskell里的type.和java或c里面的不同.

是。只是语法上不太像。也可以说不是,因为那是lambda的"1.5版"(我的“术语”,Scheme中的是1.0版,学名“一阶lambda演算”) ——Curry化算子。Curry化算子认为,一切都是函数(包括普通数据),但如果这个数据的产生式中每一项都是严格的(比如 num = 4 + 3, 3、4都是可以直接推导而不需要进行惰性化的),那么这个数据可以免除其作为函数的义务。对于产生式中有需要推导的数据,Haskell仍将其表示为普通 数据(因为类型可以直接推导来确定。只要产生它的表达式中函数调用存在,那么就会被认作函数;但是它的类型只需要一步即可推导,所以在Haskell中,它“看上去”是普通数据。)。
fact 0 = 1
fact n = n * fact (n-1) -- 这是函数,要推导
num = 5 + fact 4 -- 这个是事实上是函数,但类型上看不出来
另外,之所以haskell中的函数全是lambda的表示,和它的类型系统也有关系。前面说了,Haskell中对函数的理解已经超越了数学映 射1.5倍,重点在于对参数列表的理解。数学映射和一阶lambda都认为参数是连续的、一次传递一批,就像Scheme中那样:
(function arg1 arg2)
但Curry化算子认为参数是不连续的、可以分段传递(前提是个数事先固定),每当传递结束而参数不够是,自动转换为一个期待余下参数的函数。这就意味着,如果用Scheme的语法来说明Curry化算子就成了这样:
((+ 1) 2) ;调用一个固定参数个数为两个的函数
这句代码都将行得通!
(map (+ 1) '(1 4 2 5 2))
这对于Scheme来说是非常荒唐的(用宏另当别论),但对于Haskell这是基础:
map (+1) [1, 4, 2, 5, 2]
所以,Haskell的类型系统中对于函数类型的表示才会是那么多个箭头:因为,只要需要推导,就有函数:
Main> :t (+1)
flip (+) 1 :: Num a => a -> a
看出来了吗?不连续的类型导出过程,和java/c等等等等最大的不同点。
至于Haskell类型系统的核心力量——静态多态类型推断,讲起来是在很麻烦。去看中文版的ML语言的书里讲的很详细。

No comments: