Maybe/Option のリストから普通のリストへ
Ocaml の時は自作したけど、Scala と Haskell は結構簡単にできる。
scala> List(Some(4), Some(2), None, Some(9), None, Some(0)) flatMap (x => x) res0: List[Int] = List(4, 2, 9, 0)
> [Just 4, Just 2, Nothing, Just 9, Nothing, Just 0] >>= maybe [] return [4,2,9,0]
ただ、Haskell は普通に bind id しようとすると怒られる。
> [Just 4, Just 2, Nothing, Just 9, Nothing, Just 0] >>= id <interactive>:1:55: Couldn't match expected type `[b]' against inferred type `Maybe t' In the second argument of `(>>=)', namely `id' In the expression: [Just 4, Just 2, Nothing, Just 9, ....] >>= id In the definition of `it': it = [Just 4, Just 2, Nothing, ....] >>= id
for/do 構文を使っても書ける。
実際、TDDBC 名古屋初日の、自分の卓の Scala 組は for 式を上手いこと使っていた。
OCaml ももっと自由に使えるように勉強していこう。
liftとか
liftで遊んでみる。
> :t map map :: (a -> b) -> [a] -> [b] > :t fmap fmap :: (Functor f) => (a -> b) -> f a -> f b > :t liftM liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r > :t liftM2 liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r > :t ap ap :: (Monad m) => m (a -> b) -> m a -> m b > :t liftM (+) liftM (+) :: (Num a1, Monad m) => m a1 -> m (a1 -> a1) > :t liftM2 (+) liftM2 (+) :: (Num a1, Monad m) => m a1 -> m a1 -> m a1 > :t liftM2 id liftM2 id :: (Monad m) => m (a2 -> r) -> m a2 -> m r > liftM2 (+) [1..4] [3,4] [4,5,5,6,6,7,7,8] > liftM (+) [1..4] `ap` [3,4] [4,5,5,6,6,7,7,8] > ap [succ,(*2)] [1..4] [2,3,4,5,2,4,6,8] > :t liftM (+) [1..4] liftM (+) [1..4] :: (Num a1, Enum a1) => [a1 -> a1] > map (\f -> f 10) (liftM (+) [1..4]) [11,12,13,14] > liftM (+) [1..4] >>= return . (\f -> f 10) [11,12,13,14]
do みたいな for
Scala の for を Haskell の do みたいに使ってみる。
f :: Maybe Int -> Maybe Int -> Maybe Int f am bm = do a <- am b <- bm let c = a + b return (2 * c)
> f (Just 3) (Just 1) Just 8 > f Nothing Nothing Nothing > f (Just 3) Nothing Nothing > f Nothing (Just 1) Nothing
scala> def f(am:Option[Int], bm:Option[Int]) = for { | a <- am | b <- bm | c = a + b | } yield { | 2 * c | } f: (am: Option[Int],bm: Option[Int])Option[Int] scala> f(Some(3),Some(1)) res0: Option[Int] = Some(8) scala> f(None,None) res1: Option[Int] = None scala> f(Some(3),None) res2: Option[Int] = None scala> f(None,Some(1)) res3: Option[Int] = None
おー。
foldを使ってfoldを作る
foldr/foldl を使って、foldl/foldrを作ってみる。
myFoldL :: (a -> b -> a) -> a -> [b] -> a myFoldL f y xs = foldr (\x g a -> g $ f a x) id xs y myFoldR :: (a -> b -> b) -> b -> [a] -> b myFoldR f y xs = foldl (\g x a -> g $ f x a) id xs y -- 間違い : 適用が右から myFoldLb :: (a -> b -> a) -> a -> [b] -> a myFoldLb f y xs = foldr (\x g a -> f (g a) x) id xs y -- 間違い : 適用が左から myFoldRb :: (a -> b -> b) -> b -> [a] -> b myFoldRb f y xs = foldl (\g x a -> f x $ g a) id xs y
> foldl (flip (:)) [0] [1..3] [3,2,1,0] > myFoldL (flip (:)) [0] [1..3] [3,2,1,0] > myFoldLb (flip (:)) [0] [1..3] [1,2,3,0] > foldr (:) [0] [1..3] [1,2,3,0] > myFoldR (:) [0] [1..3] [1,2,3,0] > myFoldRb (:) [0] [1..3] [3,2,1,0]
第2要素の時の展開 (x = 2, g = (3:)/(1:), a = [0]) まで辿ってようやく分かった・・・
Yコンビネータ
フィボナッチと階乗やってみる。
> let y f = f $ y f > :i y y :: (b -> b) -> b -- Defined at <interactive>:1:4 > y (\f n -> if n < 2 then n else f (n-1) + f (n-2)) 7 13 > y (\f n -> if n < 2 then n else f (n-1) + f (n-2)) 100 Interrupted. ← (´・ω・`)ショボーン > y (\f (a,b) m -> if m < 2 then a else f (b, a + b) (m - 1)) (1,1) $ 7 13 > y (\f (a,b) m -> if m < 2 then a else f (b, a + b) (m - 1)) (1,1) $ 100 354224848179261915075
フィボナッチ。
> y (\f n -> if n < 2 then n else n * f (n-1)) 10 3628800 > y (\f n -> if n < 2 then n else n * f (n-1)) 100 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 > y (\f a b -> if b < 2 then a else f (a*b) (b-1)) 1 $ 10 3628800 > y (\f a b -> if b < 2 then a else f (a*b) (b-1)) 1 $ 100 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
階乗。
RWH 4章練習問題1
なんか作るのにすごい時間かかった・・・
- リストを述語で分割
splitWith :: (a -> Bool) -> [a] -> [[a]] splitWith f [] = [] splitWith f xs = case span f xs of (a,b) -> a : (splitWith f $ snd $ span (not . f) b)
> splitWith (/= 'a') "igaiahaidihoihihoaofha" ["ig","i","h","idihoihiho","ofh"]
- テキストの行列入れ替え
import Data.List inversionStr = unlines . transpose . fill . lines where fill xss = addBranks (maxLength xss) xss -- maxLength = foldl (\a b -> max a $ length b) 0 maxLength = maximum . map length -- addBranks n [] = [] -- addBranks n (xs:xss) = (addBrank n xs) : (addBranks n xss) addBranks n = map (addBrank n) addBrank n xs = xs ++ (brank $ n - length xs) -- brank 0 = [] -- brank n = ' ':(brank $ n - 1) brank n = take n $ repeat ' '
> putStrLn $ inversionStr "hello\nworld\naaa\nbbbbb\nccccccc\ndd\n" hwabcd eoabcd lrabc ll bc od bc c c
- おまけ
zipWithN を作ってみる。
import Data.List zipWithN f = map (foldl1 f) . transpose
> zipWithN (+) [[1,2,3],[4,5,6],[7,8,9]] [12,15,18]
transpose すげぇ。
リストとか
Scalaでやってたやつとか。
- 平方数
> take 10 $ zipWith (*) [1..] [1..] [1,4,9,16,25,36,49,64,81,100] > take 10 $ map (\x -> x * x) [1..] [1,4,9,16,25,36,49,64,81,100]
- 総和と総積
> foldl (+) 0 [1..10] 55 > foldl (*) 1 [1..10] 3628800 > foldl1 (+) [1..10] 55 > foldl1 (*) [1..10] 3628800
- 追記:FizzBuzz
fizzbuzz = map f [1..] where f x = case (mod x 3, mod x 5) of (0,0) -> "FizzBuzz" (0,_) -> "Fizz" (_,0) -> "Buzz" _ -> show x
> take 20 fizzbuzz ["1","2","Fizz","4","Buzz","Fizz","7","8","Fizz","Buzz","11","Fizz","13","14","FizzBuzz","16","17","Fizz","19","Buzz"]
インデントにはまるなどしていた。
中置関数
map とかって、中置で使うとOO系言語と逆になるんだよなぁ・・
> :info map map :: (a -> b) -> [a] -> [b] -- Defined in GHC.Base > (\x -> x + 1) `map` [1..10] [2,3,4,5,6,7,8,9,10,11] > succ `map` [1..10] [2,3,4,5,6,7,8,9,10,11] > let myMap a b = map b a > [1..10] `myMap` (\x -> x + 1) [2,3,4,5,6,7,8,9,10,11] > [1..10] `myMap` succ [2,3,4,5,6,7,8,9,10,11]
意味的には、「関数 map リスト」の方が合ってるのか・・・?
Haskellやる!
Real World Haskell―実戦で学ぶ関数型言語プログラミング が研究室に入ったので、本格的に Haskell やってみようかと。
とりあえず、3章まで読んだ。
目指せリア充!
(注:「Real World Haskell充」の略)
- 小ネタ: 3項演算子
> let (+++) a b c = a + b + c > 2 +++ 4 $ 5 11
(第一項) (演算子) (第二項) $ (第三項) 的な。
myFact n = fact n primes where primes = primes' [2..] primes' (x:xs) = x : (primes' $ filter (\a -> mod a x /= 0) xs) fact n (pn:pns) | n == 1 = [] | (floor $ sqrt $ fromInteger n) < pn = [n] | mod n pn == 0 = pn : (fact (div n pn) (pn:pns)) | otherwise = fact n pns
where かっけぇ!
参考:Haskell vs Ruby: Netsphere Laboratories