Churchエンコーディングのリストにパッケージcata
から使えるようにしたいです。recursion-schemes
type ListC a = forall b. (a -> b -> b) -> b -> b
便宜上二等式を使いましたが、気にしません。newtype
必要に応じてを追加したり、GADT を使用したりしてください。
Church エンコーディングの考え方は広く知られており、単純です。
three :: a -> a -> a -> List1 a
three a b c = \cons nil -> cons a $ cons b $ cons c nil
基本的に「未指定の抽象」cons
でありnil
、「通常の」コンストラクターの代わりに使用されます。私はすべてがこの方法でエンコードできると信じています(Maybe
、ツリーなど)。
List1
が実際に通常のリストと同型であることを示すのは簡単です:
toList :: List1 a -> [a]
toList f = f (:) []
fromList :: [a] -> List1 a
fromList l = \cons nil -> foldr cons nil l
したがって、その基本ファンクターはリストのファンクターと同じであり、それを実装project
してからの機構を使用できるはずrecursion-schemes
です。
でもできなかったので、「どうしたらいいの?」というのが私の質問です。通常のリストの場合は、パターン マッチのみを実行できます。
decons :: [a] -> ListF a [a]
decons [] = Nil
decons (x:xs) = Cons x xs
関数のパターン マッチができないため、フォールドを使用してリストを分解する必要があります。project
通常のリストの折り畳みベースを書くことができます:
decons2 :: [a] -> ListF a [a]
decons2 = foldr f Nil
where f h Nil = Cons h []
f h (Cons hh t) = Cons h $ hh : t
ただし、教会でエンコードされたリストには適用できませんでした。
-- decons3 :: ListC a -> ListF a (ListC a)
decons3 ff = ff f Nil
where f h Nil = Cons h $ \cons nil -> nil
f h (Cons hh t) = Cons h $ \cons nil -> cons hh (t cons nil)
cata
次の署名があります。
cata :: Recursive t => (Base t a -> a) -> t -> a
リストで使用するには、次のものが必要です。
- を使用してリストの基本ファンクタ型を宣言するには
type family instance Base (ListC a) = ListF a
- 実装する
instance Recursive (List a) where project = ...
私は両方のステップで失敗します。