ふつける(2) - 3章(1) 型の練習
全然ふつける読んでなかった!!文法すら忘れてた状態だったので、1章から読み直してた。やっと3章デス。型ってムズカシイ!!
型の練習
3章のtranslateを改造して型の練習です。+は1足す。-は1引く。という言語。
input :: String input = "+++++++++----++--+++-----" translate :: Char -> Int translate '+' = 1 translate '-' = -1 calc :: String -> Int calc s = foldl (\a b -> a + b) 0 $ map translate s ans :: Int ans = calc input
Haskellのmapステキ!!
translateを手続きに変えよう。
input :: String input = "+++++++++----++--+++-----" translate :: Char -> (Int -> Int) translate '+' = (\a -> a + 1) translate '-' = (\a -> a - 1) calc :: String -> Int calc s = foldl (\a b -> b a) 0 $ map translate s ans :: Int ans = calc input
ちょっと拡張出来そうな感じになってきた。
ふふ。型がわかってきたぞ。
さて、0の所をリストに変えて、空白区切りで++,--演算子にしよう。
input :: String input = "++ ++ ++ -- -- -- ++ ++" translate :: String -> ([Int] -> [Int]) translate "++" = (\a -> (head a) + 1 : tail a) translate "--" = (\a -> (head a) - 1 : tail a) calc :: String -> Int calc s = head $ foldl (\a b -> b a) [0] $ map translate $ words s ans :: Int ans = calc input
やばぁ〜い楽しい!!
文字 -> 数字がホシイ。
やっぱり1文字にして、激しく地道に行ってみる。
input :: String input = "34+12+-" translate :: Char -> ([Int] -> [Int]) translate '+' = (\a -> (head a) + (head $ tail a) : (tail $ tail a)) translate '-' = (\a -> (head $ tail a) - (head a) : (tail $ tail a)) translate '0' = (\a -> 0 : a) translate '1' = (\a -> 1 : a) translate '2' = (\a -> 2 : a) translate '3' = (\a -> 3 : a) translate '4' = (\a -> 4 : a) translate '5' = (\a -> 5 : a) translate '6' = (\a -> 6 : a) translate '7' = (\a -> 7 : a) translate '8' = (\a -> 8 : a) translate '9' = (\a -> 9 : a) calc :: String -> Int calc s = head $ foldl (\a b -> b a) [] $ map translate s ans :: Int ans = calc input
4って出ました!!いえぃ。
しかし、スゲー地道だ・・・(汗
やべぇ。Haskell楽しい〜
HaskellとSchemeの違い
HaskellとSchemeは全然違うような気がしてきた。リストの比較をしてみる。
Schemeだと、
gosh> (use srfi-1) gosh> (eq? (iota 10) (iota 10)) #f
ポインタ同士比較してるから、違うモノ。
Haskellだと、
Hugs> [1..10] == [1..10] True
えぇぇぇぇ。いっしょ。「同一性の比較は無い」って書いてある。
効率の事を考えたら凄く無駄な気がするんだ。うぅん。謎だ謎。
そうか!!参照透明性があるから、一緒のものにしちゃっても構わない訳だ。
いや。むしろ同一性が邪魔になる場合があるっぽい。うは。Haskellおもろいかも。
Haskellな疑問
わからない所を書いておこう。
- ifがまだ掴めてない。
- condがホシィ。
- cons,car,cdrがホシィ。[]が無いとリストは作れない?
- わかった。タプルだ。6章まで待ち。
- headとtailで、リストのcar,cdr的な事が可能。:でcons。
- 入出力がイマイチ・・・
- 今の所のモナドのイメージを書いておこう
Haskell初心者によるモナドのイメージ
input = readFile "./USA-states.txt"
とやりたかったけど、これはダメで、inputは,IO Stringであって、Stringじゃない!!
つまり、
現実の世界 入力 -> モナド -> 出力 | A V | Haskellの世界
となってるから、現実の世界の事は現実の世界で処理して、Haskellの世界の事はHaskellの世界の中で処理しなければならない。
monado :: IO () monado = do cs <- readFile "./USA-states.txt" putStr $ haskell_world cs haskell_world s = s
doの中は現実世界で、monadoが現実世界と、Haskellの世界を繋いでる。というのが、今のイメージ。
間違ってると思う。
もうちょい考え直すと
現実の世界 | A V | 過去 -> モナド -> 未来 | A V | Haskellの世界
IO ()という「適当な型」を付けておけば、Haskellの世界では、何もやってねぇ。という事になる。
まだ罠がありそうだけど、大体わかってきた気がする。
Schemeでモナド
つまり、
(define (monado any) (any) "世界は変わらない") (monado (lambda () (display "hello") (newline)))
monadoの中で何をやっても、常に返す値は一緒。モナドは参照透明性を保ちつつ、入出力を可能にすると。
チェーンのように繋ぐ必要がありそうだけど、基本的にはこんな感じか。
もうちょっと発展
IOをチェーンのように数珠繋ぎにする。
(define (monado any) (any 'IO)) (monado (lambda (io) (nl (hello io)))) (define (hello io) (display "hello") io) (define (nl io) (newline) io)
これで参照透明性が保てるよね。
やっべ。モナドわかっちゃった!!