《Haskell趣学指南 Learn You a Haskell for Great Good!》-代码实验
doubleMe x = x + x doubleUs x y = doubleMe x + doubleMe y doubleSmallNumber x = if x>100 then x else x * 2 doubleSmallNumber' x = (if x>100 then x else x * 2) + 1 boomBangs xs = [if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x] length' xs = sum [1 | _ <- xs] removeNonUpperCase st = [c | c <- st, c `elem` ['A'..'Z']] rightTriangles = [ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2] addThree x y z = x + y + z lucky :: Int -> String lucky 7 = "You are lucky 7" lucky x = "Sorry, you're out of luck, pal!" addVectors :: (Double,Double) -> (Double,Double) -> (Double,Double) addVectors (x1,y1) (x2,y2) = (x1+x2, y1+y2) head' :: [a] -> a head' [] = error "can't call head on an empty list, dummy!" head' (x:_) = x head'' :: [a] -> a head'' xs = case xs of [] -> error "No head for empty list!" (x:_) -> x tell :: (Show a) => [a] -> String tell [] = "list is empty!" tell (x:[]) = "list has 1 elem:" ++ (show x) tell (x:y:[]) = "list has 2 elem:" ++ (show x) ++ " and :" ++ show y tell (x:y:_) = "list has more then 2 elem, front 2 is :" ++ (show x) ++ " and :" ++ show y firstLetter :: String -> String firstLetter "" = "Empty string!" firstLetter all@(x:_) = "The first letter of [" ++ all ++ "] is:" ++ [x] bmiTell :: Double -> String bmiTell bmi | bmi <= 18.5 = "You're under weight" | bmi <= 25.0 = "You're supposed normal." | bmi <= 30.0 = "You're fat!" | otherwise = "You're a whale, congratulations!" bmiTell' :: Double -> Double -> String bmiTell' weight height | weight / height ^ 2 <= 18.5 = "You're under weight" | weight / height ^ 2 <= 25.0 = "You're supposed normal." | weight / height ^ 2 <= 30.0 = "You're fat!" | otherwise = "You're a whale, congratulations!" bmiTell'' :: Double -> Double -> String bmiTell'' weight height | bmi <= 18.5 = "You're under weight" | bmi <= 25.0 = "You're supposed normal." | bmi <= 30.0 = "You're fat!" | otherwise = "You're a whale, congratulations!" where bmi = weight / height ^ 2 max' :: Ord a => a -> a -> a max' x y | x < y = y | otherwise = x calcBmis :: [(Double,Double)] -> [Double] calcBmis xs = [ bmi w h | (w,h) <- xs] where bmi weight height = weight / height ^ 2 cylinder :: Double -> Double -> Double cylinder r h = let sideArea = 2 * pi * r * h topArea = pi * r ^ 2 in sideArea + 2 * topArea calcBmis' :: [(Double, Double)] -> [Double] calcBmis' xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2] describeList :: [a] -> String describeList ls = "This list is " ++ what ls where what [] = "empty." what [x] = " a single list." what xs = " a longer list." --递归 maximum' :: (Ord a) => [a] -> a maximum' [] = error "maximum' of empty list" maximum' [x] = x maximum' (x:xs) = max x (maximum' xs) replicate' :: Int -> a -> [a] replicate' n x | n <= 0 = [] | otherwise = x : replicate' (n-1) x take' :: (Num i, Ord i) => i -> [a] -> [a] take' n _ | n <= 0 = [] take' _ [] = [] take' n (x:xs) = x : take' (n-1) xs reverse' :: [a] -> [a] reverse' [] = [] reverse' (x:xs) = reverse' xs ++ [x] elem' :: (Eq a) => a -> [a] -> Bool elem' a [] = False elem' a (x:xs) | a == x = True | otherwise = a `elem'` xs --快速排序 quicksort :: (Ord a) => [a] -> [a] quicksort [] = [] quicksort (x:xs) = let smallerOrEqual = [a | a <- xs, a <= x] larger = [a | a <- xs, a > x] in quicksort smallerOrEqual ++ [x] ++ quicksort larger quicksort' :: (Ord a) => [a] -> [a] quicksort' [] = [] quicksort' (x:xs) = let smallerOrEqual = filter (<=x) xs larger = filter (>x) xs in quicksort' smallerOrEqual ++ [x] ++ quicksort' larger {- 第5章 高阶函数 柯里函数: 本质上,Haskell的所有函数都只有一个参数,我们见过所有 多参数的函数,都是“柯里函数”,柯里函数不会一次性取完所有的参数, 而是在每次调用时只取一个参数,并返回一个一元函数来取下一个参数, 以此类推。我们以部分参数来调用某函数,返回一个部分应用(partial application) 函数。如: let f = (max 1 ) in f (-100) -} divideByTen :: (Floating a) => a -> a divideByTen = (/10) divide200 :: (Floating a) => a -> a divide200 = (200 /) --函数执行两次 applyTwice :: (a -> a) -> a -> a applyTwice f x = f (f x) zipWith' :: (a->b->c) -> [a] -> [b] -> [c] zipWith' _ [] _ = [] zipWith' _ _ [] = [] zipWith' f (x:xs) (y:ys) = f x y : (zipWith' f xs ys) flip' :: (a->b->c) -> b -> a -> c flip' f y x = f x y --map,filter {-通过foldl函数进行左折叠,它从列表的左端开始折叠,用初始值 和列表的头部调用二元函数,得到一个新的累加值,并用新的累加值与列表 的下一个元素调用二元函数,依次类推-} sum' :: (Num a) => [a] -> a sum' xs = foldl (\acc x -> acc + x) 0 xs {- "折叠": foldl1与foldr1的行为与 foldl和foldr相似, 只是无需要明确提供初始值-} reverse1' :: [a] -> [a] reverse1' = foldl (\acc x -> x : acc) [] reverse1'' :: [a] -> [a] reverse1'' = foldl (flip (:)) [] product' :: Num a => [a] -> a product' = foldl (*) 1 {-扫描: scanl,scanr和foldl,foldr相似,不过它们会将累加值的所有变动 记录到一个列表中。也有 scanl1,scanr1与折叠foldl1,foldr1类似-} --自然数平方根之和累加,到哪个数时,累加值超过1000? sqrtSums :: Int sqrtSums = length(takeWhile (<1000) (scanl1 (+) (map sqrt [1..]))) + 1