小学期选了一门《函数程序设计》的专选课,学习了haskell语言,简单总价一下这门课。
先说说这门语言的一些特点:
一、Lazyevaluation
如 const a b = a
const 5 6 = 5
const 5 inf_loop =5
即使inf_loop无法计算出来,但是const还是能算出结果。
Lazy evaluation就是只计算需要的那部分结果而忽略掉剩下的部分,可以完成一些别的语言做不到的计算。
二、循环
Haskell里面没有循环,取而代之的是递归(recursion)
如计算阶乘的第n项,一般是用从1到n循环累乘来实现,而haskell只用两行
Factorial 0 = 1
Factorial n = n * factorical (n-1)
除了自己定义的递归,还有一些已经写好的函数帮助实现循环,如map,filter,foldr
map:map :: (a -> b) -> [a] -> [b]
filter:filter :: (a -> Bool) -> [a] -> [a]
foldr:foldr :: (a -> b -> b) -> b -> [a] -> b
而这些函数都是可以通过递归来实现的,比如map:
map f [] = []
map f (x:xs) = f x : map f xs
三、lambda表达式
除了已经定义的函数,还可以用lambda表达式临时定义新的函数
如 sq x = (\x -> x*x)
\ 后面跟传入的参数,-> 后面跟返回的值
四、数据类型
允许多个构造符的存在
如:data Tree a = Node (Tree a)(Tree a) | Leaf a | Empty
data表示后面声明的是一个数据类型(数据类型是大写开头,而定义函数方法则是小写开头)
Tree是数据类型的名称,可以由Node,Leaf或者Empty构造符来构造
A表示的是参数的数据类型,这里与构造符的a保持一致意思即是同样一个类型
基于这些比较基本的特点,这次课还主要讲了适用于各种类型的迭代构造的方法catamorphism,paramorphism,对于简单的数据类型来说,对应的就是foldr和unfold
比如对于一个数据类型data Tree a = Node (Tree a)(Tree a) | Leaf a | Empty
有catamorphism:
cataT ns ls es (Node t1 t2) = ns (cataT nsls es t1) (cataT ns ls es t2)
cataT ns ls es (Leaf a) = ls a
cataT ns ls es Empty = es
paramorphism:
paraT ns ls es (Node t1 t2) = ns (cataT nsls es t1) t1 (cataT ns ls es t2) t2
paraT ns ls es (Leaf a) = ls a
paraT ns ls es Empty = es
cataT和paraT都是方法的名字,
(1)接受三个方法的参数(分别对应处理三个构造符构造的数据类型),然后接受一个Tree类型的参数,
(2)其中如果是Node的话由于是有两个Tree类型的参数构成,所以对于无法直接求解的Tree类型,选择的是继续递归下去,
(3)而para和cata的不同也体现在这里,para此时会多传入t1和t2这两个Tree类型作为ns函数的参数。(如果这里Node是Node a (Tree a) (Tree a)的话,则cata和para都要传入a到ns的参数里面去),
(4)Leaf和Empty构造符并没有接收Tree的参数,所以不需要用到递归(这个递归专门针对Tree这个数据类型来设定的)。
这就大大简便了对某一数据类型的各种操作的实现,由于cata和para是已经设计好的,程序员需要做的只是填空(把ns,ls和es填好即可)就可以根据编写这三个函数来实现对Tree类型的递归,比如可以对Tree进行遍历,对Tree的Leaf项进行相加等等操作,只需改变ns,ls和es即可。
总结:
这门课虽然是外教上的但是还是能够在最后两天听懂他的话了。。。对自己的学习能力是一个比较大的考验吧,学习到一种新的编程思路和语言也是收获蛮大的,但毕竟只是8天,只能做到略懂~