npo*_*cop 5 recursion haskell church-encoding catamorphism recursion-schemes
我希望能够cata从recursion-schemes包中使用Church编码中的列表.
type ListC a = forall b. (a -> b -> b) -> b -> b
Run Code Online (Sandbox Code Playgroud)
为方便起见,我使用了二级排序,但我不在乎.newtype如果您觉得有必要,请随意添加,使用GADT等.
教会编码的概念众所周知且简单:
three :: a -> a -> a -> List1 a
three a b c = \cons nil -> cons a $ cons b $ cons c nil
Run Code Online (Sandbox Code Playgroud)
基本上是"抽象未指定" cons,nil而不是"正常"构造函数.我相信一切都可以用这种方式编码(Maybe树木等).
很容易证明它List1与普通列表确实是同构的:
toList :: List1 a -> [a]
toList f = f (:) []
fromList :: [a] -> List1 a
fromList l = \cons nil -> foldr cons nil l
Run Code Online (Sandbox Code Playgroud)
因此它的基础仿函数与列表相同,应该可以实现project它并使用来自的机器recursion-schemes.
但我不能,所以我的问题是"我该怎么做?".对于普通列表,我可以模式匹配:
decons :: [a] -> ListF a [a]
decons [] = Nil
decons (x:xs) = Cons x xs
Run Code Online (Sandbox Code Playgroud)
由于我无法对函数进行模式匹配,因此我必须使用折叠来解构列表.我可以写一个基于折叠的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
Run Code Online (Sandbox Code Playgroud)
但是我无法将其改编为教会编码列表:
-- 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)
Run Code Online (Sandbox Code Playgroud)
cata 有以下签名:
cata :: Recursive t => (Base t a -> a) -> t -> a
Run Code Online (Sandbox Code Playgroud)
要在我的列表中使用它,我需要:
type family instance Base (ListC a) = ListF ainstance Recursive (List a) where project = ...我在两个步骤都失败了.
事实证明,包装纸newtype是我错过的关键步骤。这是代码以及来自 的示例变形recursion-schemes。
{-# LANGUAGE LambdaCase, Rank2Types, TypeFamilies #-}
import Data.Functor.Foldable
newtype ListC a = ListC { foldListC :: forall b. (a -> b -> b) -> b -> b }
type instance Base (ListC a) = ListF a
cons :: a -> ListC a -> ListC a
cons x (ListC xs) = ListC $ \cons' nil' -> x `cons'` xs cons' nil'
nil :: ListC a
nil = ListC $ \cons' nil' -> nil'
toList :: ListC a -> [a]
toList f = foldListC f (:) []
fromList :: [a] -> ListC a
fromList l = foldr cons nil l
instance Recursive (ListC a) where
project xs = foldListC xs f Nil
where f x Nil = Cons x nil
f x (Cons tx xs) = Cons x $ tx `cons` xs
len = cata $ \case Nil -> 0
Cons _ l -> l + 1
Run Code Online (Sandbox Code Playgroud)