本帖最后由 轻舟过 于 2012-8-1 00:55 编辑
最近两天做了Haskell 99题中的前20道
函数式编程解决问题的思路还真是不一样
还有函数式编程是不是研究Lisp更好一点。。
题目链接在这里:http://www.haskell.org/haskellwiki/99_questions
相应的还有Prolog、Lisp、Perl、OCaml的99题
论坛的SyntaxHighlighter插件怎么没有Haskell的语法高亮
[mw_shl_code=text,true]-- #1
myLast :: [a] -> a
myLast (x:[]) = x
myLast (x:xs) = myLast xs
-- #2
myButLast :: [a] -> a
myButLast (x1:x2:[]) = x1
myButLast (x1:x2:xs) = myButLast (x2:xs)
-- #3
elementAt :: [a] -> Int -> a
elementAt (x:xs) 1 = x
elementAt (x:xs) idx = elementAt xs (idx - 1)
-- #4
myLength :: [a] -> Int
myLength xs = foldl (+) 0 $ map (\x -> 1) xs
-- #5
myReverse :: [a] -> [a]
myReverse = foldl (\xs x-> x:xs) []
-- #6
isPalindrome :: (Eq a) => [a] -> Bool
isPalindrome xs = xs == myReverse xs
data NestedList a = Elem a | List [NestedList a] deriving (Show)
-- #7
flatten :: NestedList a -> [a]
flatten (Elem x) = [x]
flatten (List lst) = foldl (++) [] $ map flatten lst
-- #8
compress :: (Eq a) => [a] -> [a]
compress [] = []
compress all@(x:xs) = (head $ takeWhile (==x) all):compress(dropWhile (==x) all)
-- #9
pack :: (Eq a) => [a] -> [[a]]
pack [] = []
pack all@(x:xs) = (takeWhile (==x) all):pack(dropWhile (==x) all)
-- #10
encode :: (Eq a) => [a] -> [(Int, a)]
encode [] = []
encode all@(x:xs) = ((myLength $ takeWhile (==x) all), x):encode(dropWhile (==x) all)
data RunLengthCode a = Single a | Multiple Int a deriving (Show)
-- #11
encodeModified :: (Eq a) => [a] -> [RunLengthCode a]
encodeModified [] = []
encodeModified lst = map toRunLengthCode $ encode lst
where toRunLengthCode pair = if fst pair == 1 then (Single (snd pair)) else (Multiple (fst pair) (snd pair))
-- #12
decodeModified :: [RunLengthCode a] -> [a]
decodeModified [] = []
decodeModified ((Single x):xs) = [x] ++ decodeModified(xs)
decodeModified ((Multiple len x):xs) = (replicate len x) ++ decodeModified(xs)
-- #13
encodeDirect :: (Eq a) => [a] -> [RunLengthCode a]
encodeDirect [] = []
encodeDirect all@(x:xs) = code:encodeDirect(dropWhile (==x) all)
where len = myLength $ takeWhile (==x) all
code = if len == 1 then (Single x) else (Multiple len x)
-- #14
dupli :: [a] -> [a]
dupli [] = []
dupli (x:xs) = [x, x] ++ dupli(xs)
-- #15
repli :: [a] -> Int -> [a]
repli [] _ = []
repli (x:xs) cnt = (replicate cnt x) ++ (repli xs cnt)
-- #16
{-
- dropEvery = flip $ \n -> map snd . filter ((n/=) . fst) . zip (cycle [1..n])
-}
dropEvery :: [a] -> Int -> [a]
dropEvery lst cnt = map snd $ filter (\p -> (fst p) `mod` cnt /= 0) $ zip [1..] lst
-- #17
split :: [a] -> Int -> ([a], [a])
split lst len = (take len lst, drop len lst)
-- #18
slice :: [a] -> Int -> Int -> [a]
slice lst start end = fst $ split (drop (start - 1) lst) (end - start + 1)
-- #19
rotate :: [a] -> Int -> [a]
rotate lst num = (drop len lst) ++ (take len lst)
where lstLen = length lst
len = (num `mod` lstLen + lstLen) `mod` lstLen
-- #20
removeAt :: Int -> [a] -> (a, [a])
removeAt num lst = (head lstTail, (take (num - 1) lst) ++ (tail lstTail))
where lstTail = drop (num - 1) lst
[/mw_shl_code]
然后还有spoj上的TEST
[mw_shl_code=text,true]main = do
line <- getLine
if line == "42"
then getContents
else do
putStrLn line
main[/mw_shl_code]
刚刚发现对函数进行fmap实际上就是 . 的效果,好神奇
像$感觉就是用来少写几个括号的?
参数模式匹配确实很爽啊,像C语言写类似的东西时候都是写if什么什么的,感觉haskell是把不同情况下的代码完全分离开了
像(5+)这种部分参数绑定的也很神奇的
Haskell的自动类型推断好强大
最后你有什么关于Haskell的资料可以推荐的吗,像书、网站、练习题什么的都可以。
目前在看的是《Learn you a Haskell for Great Good!》
[查看全文]
Haskell的标点符号可以引入很多语法糖…… . 和 $ 这种都算吧……
然后还有Control.Arrow库里有一坨奇怪的标点符号……跟Monad相关的,还没研究……
其它有啥我忘了……
其实我觉得像 (5+) 这种写法 和 参数模式匹配也很爽的……不过貌似不能叫语法糖……
感觉Haskell在语法上面做了不少功夫,让人写程序很舒服……我现在就觉得一个舒服的语言就可以自然的让人写出总分结构的代码来。觉得命令式语言在一个局部都是分总的感觉,先要思考用到哪些变量,然后再去做实际的事,如果以总分的思维来写光标就要跳来跳去;另外一个——感觉C的类型转换的语法也很让人不爽,因为按照正常思维都是先去想变量的名字再去思考是否做类型转换,所以感觉语法应该设定成类型出现在变量后面,这样就非常顺畅。这就是我关于语言的想法。于是发现Haskell在这一点做的不错……一切都是惰性求值所赐……虽然最后结论需要用它写点大工程才能得到……
说得有点乱…………
[查看全文]
