最近专注毕设,太久没写新东西了,该整点活了。
最近又开始去了解 haskell,之前学这语言觉得语法和之前学的差距太大因此弃坑(也或许是看得太快了),现在回过头来才发现,还挺有趣的。haskell 很有魔力,和之前学的语言又有很大差别,感觉又太过学术性……学起来确实是挺难的。
还是根据之前看的《Haskell 趣学指南》来学。这篇文章实现一下 haskell 的几个已有的函数。
replicate, repeat
replicate 接受一个整数 n 和一个元素,返回包含 n 个该元素的列表。
显然当 n 为 0 的时候返回空列表,这里约定 n 小于 0 的时候也返回空列表,明显地,这里已经获得递归的基线条件了。
| replicate' :: (Ord t, Num t) => t -> a -> [a] replicate' n elem | n <= 0 = [] | otherwise = elem : replicate' (n - 1) elem
|
repeat 生成某元素的无限列表(牛逼啊……),实现非常容易。
| repeat' :: a -> [a] repeat' elem = elem:repeat' elem
|
take, reverse, elem
take 函数从列表中取出前 n 个元素。约定 n 小于等于 0 时取得空列表,列表为空的时候取得空列表。
| take' :: (Ord t, Num t) => t -> [a] -> [a] take' n _ | n <= 0 = [] take' _ [] = [] take' n (x:xs) = x : take' (n - 1) xs
|
一个非常鬼畜的地方是,像take 3 []
这样的函数调用时会报错的,haskell 抱怨到,它不知道这个列表里的元素究竟是什么类型(即使这是一个空列表!)。同理,[]
在任何地方直接使用(不使用++和:,否则 haskell 能推断出类型,也不指定类型,如[] :: [Integer]
,这是不会报错的)都会报这个错误,而且那错误提示还挺晦涩,挺迷惑人的。
elem 检测元素是否在列表中。遍历一遍,每次查头部即可,和 lisp 版的一样。
| elem' :: Eq t => t -> [t] -> Bool elem' a [] = False elem' a (x:xs) = a == x || elem' a xs
elem' :: Eq t => t -> [t] -> Bool elem' a = foldr (\ x -> (||) (a == x)) False
|
reverse 的实现就不用多说了 8。
| reverse' :: [a] -> [a] reverse' [] = [] reverse' (x:xs) = reverse' xs ++ [x]
reverse' :: [a] -> [a] reverse' [] = [] reverse' xs = foldl (flip (:)) [] xs
|
zip, zipWith
zip 将两列表中对应位置元素一一组成元组列表,其长度为两列表中较小的一个。zipWith 方法接受一个函数和两个列表,将两列表中对应元素一一应用到函数并返回结果的列表。写起来其实和 zip 一样。
| zip' :: [a] -> [b] -> [(a, b)] zip' [] _ = [] zip' _ [] = [] zip' (x:xs) (y:ys) = (x,y):zip' xs ys
zipWith' :: (t1 -> t2 -> a) -> [t1] -> [t2] -> [a] zipWith' _ [] _ = [] zipWith' _ _ [] = [] zipWith' f (x:xs) (y:ys) = f x y:zipWith' f xs ys
|
感叹,haskell 写起这个来比其他语言优雅多了。
fold, map, filter
折叠操作:一个列表生成一个值。
折叠操作能用来编写 map 和 filter,毕竟列表也是值嘛。就这方面来说,可以认为折叠操作是对列表的最广泛的操作:以源列表为输入,输出一个值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| foldl' :: (t1 -> t2 -> t1) -> t1 -> [t2] -> t1 foldl' _ a [] = a foldl' f a (x:xs) = foldl' f (f a x) xs
foldl1' :: (p -> p -> p) -> [p] -> p foldl1' _ [] = error "empty list" foldl1' f (x:xs) = foldl' f x xs
map' :: (t -> a) -> [t] -> [a] map' _ [] = [] map' f xs = foldl' (\ x y -> x ++ [f y]) [] xs
filter' :: (a -> Bool) -> [a] -> [a] filter' _ [] = [] filter' f xs = foldl' (\ x y -> x ++ [y | f y]) [] xs
filter' :: (a -> Bool) -> [a] -> [a] filter' _ [] = [] filter' fn (x:xs) = if fn x then x : last else last where last = filter' fn xs
|
就写这些。haskell 虽然漂亮且优雅(以后要写伪代码的时候干脆就写 haskell 吧!),但是着实有点得劲。我还是先去学学 scala 吧……