Arrow.hsを読もう〜その2〜
Arrow.hsを読もう〜その1〜 - みずぴー日記の続き。Arrow.hsを読もう、30分で読める範囲だけ。
ArrowApply
instance ArrowApply (->) where app (f,x) = f x
単なる適用。(->)以外だと嬉しいんだろう、たぶん。
leftApp
-- | Any instance of 'ArrowApply' can be made into an instance of -- 'ArrowChoice' by defining 'left' = 'leftApp'. leftApp :: ArrowApply a => a b c -> a (Either b d) (Either c d) leftApp f = arr ((\b -> (arr (\() -> b) >>> f >>> arr Left, ())) ||| (\d -> (arr (\() -> d) >>> arr Right, ()))) >>> app
コメントによると、ArrowApplyをArrowChoiceにできるらしい。よし、読むか。
まず、(|||)があるから、Leftの場合とRightの場合を分けて考えよう。
Leftのときは
(\b -> (arr (\() -> b) >>> f >>> arr Left, ()))
になる。タプルになっていて分かりづらいので、1つめの関数の中身だけを取り出す。
(arr (\() -> b) >>> f >>> arr Left
左から右に流れることを考えると
\() -> Left (f b)
と同じ。
つまり、Leftの場合は、
(\() -> Left (f b),())
が得られる。
同様にRightの場合は、
(\() -> Right d,())
になる。
そしてappがタプルを潰して、Left (f b)とかRight dとかを作る。
ArrowApp便利じゃん。
ArrowLoop
-- | The 'loop' operator expresses computations in which an output value is -- fed back as input, even though the computation occurs only once. -- It underlies the @rec@ value recursion construct in arrow notation. class Arrow a => ArrowLoop a where loop :: a (b,d) (c,d) -> a b c instance ArrowLoop (->) where loop f b = let (c,d) = f (b,d) in c
さて、ループだ。
間違いなく
let (c,d) = f (b,d)
がポイントで、Haskellが遅延評価だから使える技なんだろう。コメントには、出力が入力にフィードバックしてるのがポイントだって書いてあるし。
難しすぎるから、例ベースでいこう。2007-08-18 - mad日記によるとfactはこう定義できるらしい。
fact = loop $ \(x, f) -> (f x, \n -> if n == 0 then 1 else n * f(n-1))
最終的な返り値はf x。xはfactへの引数。問題はfが何か、という点だ。
えっと、fはひとつ前の出力だから
f = \n -> if n == 0 then 1 else n * f(n-1)
となる。
普通の階乗のコードになった。なるほど、だから階乗が計算できるんか。
読んだ感想
なくしか理解できない。でも、これがコードを読んで理解できるのは、これぐらいが限界な気がする。よし、次回からはコード書くぞー。