Un'alternativa da considerare invece di DList
consiste nell'utilizzare elenchi codificati di Church. L'idea è di rappresentare un elenco come un valore opaco che sa come eseguire uno foldr
su un elenco. Ciò richiede l'utilizzo del RankNTypes
estensione:
{-# LANGUAGE RankNTypes #-}
import Prelude
import Control.Applicative
import Data.Foldable (Foldable)
import qualified Data.Foldable as F
import Data.Traversable (Traversable)
import qualified Data.Traversable as T
-- | Laws:
--
-- > runList xs cons nil == xs
-- > runList (fromList xs) f z == foldr f z xs
-- > foldr f z (toList xs) == runList xs f z
newtype ChurchList a =
ChurchList { runList :: forall r. (a -> r -> r) -> r -> r }
-- | Make a 'ChurchList' out of a regular list.
fromList :: [a] -> ChurchList a
fromList xs = ChurchList $ \k z -> foldr k z xs
-- | Turn a 'ChurchList' into a regular list.
toList :: ChurchList a -> [a]
toList xs = runList xs (:) []
-- | We can construct an empty 'ChurchList' without using a @[]@.
nil :: ChurchList a
nil = ChurchList $ \_ z -> z
-- | The 'ChurchList' counterpart to '(:)'. Unlike 'DList', whose
-- implementation uses the regular list type, 'ChurchList' doesn't
-- rely on it at all.
cons :: a -> ChurchList a -> ChurchList a
cons x xs = ChurchList $ \k z -> k x (runList xs k z)
-- | Append two 'ChurchList's. This runs in O(1) time. Note that
-- there is no need to materialize the lists as @[a]@.
append :: ChurchList a -> ChurchList a -> ChurchList a
append xs ys = ChurchList $ \k z -> runList xs k (runList ys k z)
-- | Map over a 'ChurchList'. No need to materialize the list.
instance Functor ChurchList where
fmap f xs = ChurchList $ \k z -> runList xs (\x xs' -> k (f x) xs') z
-- | The 'Foldable' instance is trivial, given the 'ChurchList' law.
instance Foldable ChurchList where
foldr f z xs = runList xs f z
instance Traversable ChurchList where
traverse f xs = runList xs step (pure nil)
where step x rest = cons <$> f x <*> rest
Lo svantaggio di questo è che non c'è efficiente tail
operazione per un ChurchList
-il piegamento una ChurchList
è economico, ma prendendo ripetuta code è costoso ...
fonte
2013-03-23 23:38:56
seguito alla Risposta di Sjoerd, un DList è efficace solo per ** building **: se hai compilato il tuo elenco e vuoi elaborarlo, devi coprirlo con 'toList', quindi elaborare l'elenco regolare. –
Quindi, perché non definiamo semplicemente 'fold (DL f) = fold (f [])'? Possiamo dimenticarci di come 'DList's sono implementati e semplicemente vederli come una rappresentazione della sequenza di elementi, e quindi implementare' Foldable' ha senso. L'implementazione di 'Functor' e' Traversable' in questo modo avrebbe probabilmente qualche insidia, ma 'Foldable' sembra abbastanza ragionevole. –
Sì, 'Pieghevole' potrebbe non essere un problema, il pacchetto ha' foldr' già e dopo tutto è abbastanza. Immagino che la ragione per cui non è stata implementata è perché l'ultimo aggiornamento era nel 2009, quando 'Foldable' non era ancora una classe di caratteri ben nota. –