Desidero poter usare il pacchetto cata
dal recursion-schemes
per gli elenchi nella codifica della Chiesa.Catamorfismi per elenchi codificati dalla Chiesa
type ListC a = forall b. (a -> b -> b) -> b -> b
Ho usato un secondo tipo per comodità, ma non mi interessa. Sentiti libero di aggiungere uno newtype
, utilizzare GADT, ecc. Se ritieni che sia necessario.
L'idea di codifica Chiesa è ampiamente noto e semplice:
three :: a -> a -> a -> List1 a
three a b c = \cons nil -> cons a $ cons b $ cons c nil
Fondamentalmente "astratto specificato" cons
e nil
sono usati al posto dei costruttori "normali". Credo che tutto possa essere codificato in questo modo (Maybe
, alberi, ecc.).
E 'facile dimostrare che List1
è davvero isomorfo a liste normali:
toList :: List1 a -> [a]
toList f = f (:) []
fromList :: [a] -> List1 a
fromList l = \cons nil -> foldr cons nil l
Così la sua functor di base è la stessa delle liste, e dovrebbe essere possibile implementare project
per esso e utilizzare i macchinari da recursion-schemes
.
Ma non potevo, quindi la mia domanda è "come faccio?". Per gli elenchi normali, posso solo pattern match:
decons :: [a] -> ListF a [a]
decons [] = Nil
decons (x:xs) = Cons x xs
Dal momento che non pattern-match di funzioni, devo usare una piega di decostruire la lista. Potrei scrivere un fold-based project
per le liste normali:
decons2 :: [a] -> ListF a [a]
decons2 = foldr f Nil
where f h Nil = Cons h []
f h (Cons hh t) = Cons h $ hh : t
Tuttavia non sono riuscito ad adattarlo per gli elenchi Chiesa-encoded:
-- 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
ha la seguente firma:
cata :: Recursive t => (Base t a -> a) -> t -> a
Per utilizzarlo con i miei elenchi, ho bisogno di:
- per dichiarare il tipo di base funtore per l'elenco utilizzando
type family instance Base (ListC a) = ListF a
- Per implementare
instance Recursive (List a) where project = ...
non riesco ad entrambe le fasi.
Qual è il tuo errore? Ho provato questo (aggiungendo 'newtype' per comodità) e funziona bene. – MigMit
Ho aggiornato la mia domanda – nponeccop
Il 'newtype' si è rivelato essenziale e non solo una comodità. Il codice funziona ora. – nponeccop