LoginSignup
13
2

Haskellのdo記法がよくわからなかった話

Last updated at Posted at 2024-04-15

はじめに

どうも Haskell 初心者です!
最近『すごいHaskellたのしく学ぼう』を勉強しました。私にとっては初めての関数型言語だったので理解で苦しむところも多くありました。

なかでも、モナドのdo記法のところで混乱したので、私が何に混乱したのかを書いておきます。

誤解のもと

8章の入出力の章で初めてdo記法が出てきたときは、この様なコードが載っていました。

main = do
    putStrLn = "Hello, what's your name?"
    name <- getLine
    putStrLn = ("Hey " ++ name ++ ", you rock!")

これを見て私は

  • do記法の中では、<-を使うことでIO()とかいう良くわからないものを剥がして代入してくれるんだな
  • do式の最後の行が返り値になるんだな

と思っていました。

認識違いの判明

ところが13章のモナドの章でその認識では説明できないコードが現れました。

-- landLeft :: Int -> (Int, Int) -> Maybe (Int, Int)
-- landRight :: Int -> (Int, Int) -> Maybe (Int, Int)

routine :: Maybe (Int, Int)
routine = do
    start <- return (0, 0)
    first <- landLeft 2 start
    Nothing
    second <- landRight 2 first
    landLeft 1 second

{-
ghci> routine
Nothing
-}

なぜか途中にあって何にも束縛していないNothingがdo式の返り値に影響を与えているのです!
ただ、当時は自分の理解と矛盾していることにも気がついておらずスルーしていました。

14章でも

logNumber :: Int -> Writer [String] Int
logNumber x = writer (x, ["Got number: " ++ show x])

multWithLog :: Writer [String] Int
multWithLog = do
    a <- logNumber 3
    b <- logNumber 5
    tell ["Gonna multtply these two"]
    return (a*b)

{-
ghci> runWriter multWithLog
(15, ["Got number: 3", "Got number: 5", "Gonna multply these two"])
-}

またしてもtellという、どの変数にも束縛されてない関数がしっかり結果に影響を与えているのです!
これを見て私も自分の認識がおかしいことに気が付きます。

do記法を脱糖してみる

do記法は糖衣構文なので、脱糖して書いてみます。それぞれ

routine :: Maybe Pole
routine = return (0, 0) 
        >>= landLeft 2 
        >> Nothing 
        >>= landRight 2 
        >>= landLeft 1
runWriter (logNumber2 3 >>= (\x
        -> logNumber2 4 >>= (\y
        -> tell ["Gonna multiply these two"] >> return(x * y) )))

と同じコードということになります。こう書くと独立していて何もしていないようにみえたNothingtellも一連のモナド適用の連鎖の一部であることがわかります。

おわりに

do記法は手続き型言語のような見た目をしていますが、各行は独立しておらず、滝のように連なっていることがわかりました。
自分と同じ勘違いをしている初心者の助けになれば幸いです。

13
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
2