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)

となる。
普通の階乗のコードになった。なるほど、だから階乗が計算できるんか。

読んだ感想

なくしか理解できない。でも、これがコードを読んで理解できるのは、これぐらいが限界な気がする。よし、次回からはコード書くぞー。