プログラミングなどなど

プログラミングに関係しそうな内容を

Haskell:whereとletを使った関数定義のスタイルについて(Stateモナド手前のfmap)

7/22から7/25と4連休だったのと、SPINからちょっと離れたいとの思いから、HaskellのFunctorからMonadの流れを勉強してみようと思い本(プログラミングHaskell 第2版)を読んでいました。読み進める中でStateモナドを定義する前のFunctorのfmap実装がぱっと理解できずに別の書籍(関数プログラミング入門 ―Haskellで学ぶ原理と技法―)にあたったのですが、こういう風に書かれていたら、個人的にはわかりやすかったかもな。と思う部分がありましたので、載せたいと思います。まぁ、慣れれば、どちらでも良いのでしょうが。

共通部分

newtype St a = MkSt (State -> (a, State))
type State = Int

app :: St a -> State -> (a, State)
app (MkSt stf) s = stf s

例1 : 「プログラミング Haskell 第2版」風

instance Functor St where
  -- fmap :: (a -> b) -> St a -> St b
  fmap f sta = MkSt (\s -> let (x, s') = app sta s
                           in
                            (f x, s'))

letを使って上から下に読める感じは好きなのですが、\s -> ... の部分が慣れないせいか、すっと頭に入りませんでした。

例2 : 「関数プログラミング入門 -Haskellで学ぶ原理と技法-」風

本の中では、StのFunctorインスタンスの定義はなく、Monadの定義のみが出てきていますが、この本の記述スタイルならこうなるだろという風で書いています。

instance Functor St where
  -- fmap :: (a -> b) -> St a -> St b
  fmap f sta = MkSt g
               where
               g s = (f x, s')
                     where (x, s') = app sta s

例1と少し変わって、MkSt g と g s = ... でsを引数にとる関数を定義し返している部分は、わかりやすい感じで好きなのですが、

... = (f x, s')
      where (x, s') = app sta

の部分は下の定義を確認して上に戻らなければならないので、部分でちょっと好きになれませんでした。

例3 : 混ぜた感じ

個人的には、例1,2を混ぜた感じの以下の様な記述だと、すっと入りそうな気がしました。

instance Functor St where
  -- fmap :: (a -> b) -> St a -> St b
  fmap f sta = MkSt g
               where
               g s = let (x, s') = app sta s
                     in
                      (f x, s')