|fib| などの通常の再帰表記を翻訳する方法を見つけようとしています。再帰表記の構造を可能な限り保持しながら、下の関数を矢印に置き換えます。さらに、矢印を調べたいと思います。このために、各 Arrow{..} クラスのコンストラクターを含むデータ型を作成しました。
フィブ:
fib 0 = 0
fib 1 = 1
fib n = fib (n-2) + fib (n-1)
私のRデータ型、このデータ型のインスタンスは、適切なコンストラクターへのマッピングで構成されています:
data R x y where
-- Category
Id :: R a a
Comp :: R b c -> R a b -> R a c
-- Arrow
Arr :: (a -> b) -> R a b
Split :: R b c -> R b' c' -> R (b,b') (c,c')
Cache :: (a -> a -> Bool) -> R a a
-- ArrowChoice
Choice :: R b c -> R b' c' -> R (Either b b') (Either c c')
-- ArrowLoop
Loop :: R (b, d) (c, d) -> R b c
-- ArrowApply
Apply :: R (R b c, b) c
|fib|の翻訳 上記の関数は、最初に次の定義をもたらしました。ただし、|fibz| の宣言の右側にある proc n のために許可されていません。Arrow Notation の文法がこれを妨げていることは知っていますが、その根本的な理由は何ですか?
fib' :: (ArrowChoice r, ArrowLoop r) => r Int Int
fib' = proc x -> do
rec fibz <- proc n -> case n of
0 -> returnA -< 0
1 -> returnA -< 1
n' -> do l <- fibz -< (n'-2)
r <- fibz -< (n'-1)
returnA -< (l+r)
fibz -<< x
上記の関数を let ステートメントを使用するように書き換えると、コンパイルが実行されます。ただし、ここで 2 つ目の問題が発生します。再帰が発生する場所を検査できるようにしたい。ただし、この場合 |fibz| 無限木です。再帰を fibz にキャプチャしたいと思います。rec が |loop| と組み合わせてそれを支援してくれることを願っています。しかし、多分私は間違っていますか?
fib'' :: (ArrowChoice r, ArrowLoop r, ArrowApply r) => r Int Int
fib'' = proc x -> do
let fibz = proc n -> case n of
0 -> returnA -< 0
1 -> returnA -< 1
n' -> do l <- fibz -< (n'-2)
r <- fibz -< (n'-1)
returnA -< (l+r)
fibz -<< x
基本的に、この種の再帰を観察することは可能ですか? (おそらく Arrow Notation の境界内でも) fix のような別のコンストラクターを追加することもできます。たぶん、変数の参照が可能になるように、変数のバインディングを観察できるはずです。ただし、これは Arrows の範囲外になります。
これについて何か考えはありますか?
更新 1:
矢印表記以外で、このフォームを思いつきました。これにより、内に再帰が隠されるapp
ため、矢印の有限表現になります。fib
ただし、内部への呼び出しをapp
最適化されたバージョンのfib
.
fib :: (ArrowChoice r, ArrowLoop r, ArrowApply r) => r Int Int
fib
= (arr
(\ n ->
case n of
0 -> Left ()
1 -> Right (Left ())
n' -> Right (Right n'))
>>>
(arr (\ () -> 0) |||
(arr (\ () -> 1) |||
(arr (\ n' -> (n', n')) >>>
(first ( arr (\ n' -> app (fib, n' - 2))) >>>
arr (\ (l, n') -> (n', l)))
>>>
(first (arr (\ n' -> app (fib, n' - 1))) >>>
arr (\ (r, l) -> (l + r)))))))
このコードは、以下の矢印表記に対応しています。
fib :: (ArrowChoice r, ArrowLoop r, ArrowApply r) => r Int Int
fib = proc n ->
case n of
0 -> returnA -< 0
1 -> returnA -< 1
n' ->
do l <- fib -<< (n'-2)
r <- fib -<< (n'-1)
returnA -< (l+r)