ふつける(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楽しい〜

HaskellSchemeの違い

HaskellSchemeは全然違うような気がしてきた。リストの比較をしてみる。

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)

これで参照透明性が保てるよね。

やっべ。モナドわかっちゃった!!