用于教会编码列表的Catamorphisms

时间:2015-07-16 21:38:30

标签: haskell recursion church-encoding catamorphism recursion-schemes

我希望能够使用cata包中的recursion-schemes来获取Church编码中的列表。

type ListC a = forall b. (a -> b -> b) -> b -> b

为方便起见,我使用了第二种类型,但我并不在意。如果您认为有必要,可以随意添加newtype,使用GADT等。

教会编码的概念众所周知且简单:

three :: a -> a -> a -> List1 a 
three a b c = \cons nil -> cons a $ cons b $ cons c nil

基本上"抽象未指明"使用consnil代替"正常"构造函数。我相信一切都可以这种方式编码(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

要将它与我的列表一起使用,我需要:

  1. 使用type family instance Base (ListC a) = ListF a
  2. 声明列表的基本仿函数类型
  3. 实施instance Recursive (List a) where project = ...
  4. 我在两个步骤都失败了。

1 个答案:

答案 0 :(得分:4)

newtype封面是我错过的关键步骤。以下是代码以及来自recursion-schemes的示例catamorphism。

{-# 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