Sök…


Anmärkningar

Funktioner som nämns här i exempel definieras med olika grader av abstraktion i flera paket, till exempel data-fix och recursion-schemes (fler funktioner här). Du kan se en mer komplett lista genom att söka på Hayoo .

Fasta punkter

Fix tar en "mall" -typ och binder den rekursiva knuten och lägger mallen som en lasagne.

newtype Fix f = Fix { unFix :: f (Fix f) }

Inuti en Fix f hittar vi ett lager av mallen f . För att fylla i f : s parameter, Fix f pluggar i sig själv . Så när du tittar in i mallen f hittar du en rekursiv förekomst av Fix f .

Så här kan en typisk rekursiv datatyp översättas till vår ram av mallar och fasta punkter. Vi tar bort rekursiva händelser av typen och markerar deras positioner med parametern r .

{-# LANGUAGE DeriveFunctor #-}

-- natural numbers
-- data Nat = Zero | Suc Nat
data NatF r = Zero_ | Suc_ r deriving Functor
type Nat = Fix NatF

zero :: Nat
zero = Fix Zero_
suc :: Nat -> Nat
suc n = Fix (Suc_ n)


-- lists: note the additional type parameter a
-- data List a = Nil | Cons a (List a)
data ListF a r = Nil_ | Cons_ a r deriving Functor
type List a = Fix (ListF a)

nil :: List a
nil = Fix Nil_
cons :: a -> List a -> List a
cons x xs = Fix (Cons_ x xs)


-- binary trees: note two recursive occurrences
-- data Tree a = Leaf | Node (Tree a) a (Tree a)
data TreeF a r = Leaf_ | Node_ r a r deriving Functor
type Tree a = Fix (TreeF a)

leaf :: Tree a
leaf = Fix Leaf_
node :: Tree a -> a -> Tree a -> Tree a
node l x r = Fix (Node_ l x r)

Vik upp en struktur ett lager åt gången

Katamorfismer , eller veck , modellerar primitiv rekursion. cata rivar ned ett fixpoint lager för lager med hjälp av en algebrafunktion (eller vikningsfunktion ) för att bearbeta varje lager. cata kräver en Functor instans för Functor f .

cata :: Functor f => (f a -> a) -> Fix f -> a
cata f = f . fmap (cata f) . unFix

-- list example
foldr :: (a -> b -> b) -> b -> List a -> b
foldr f z = cata alg
    where alg Nil_ = z
          alg (Cons_ x acc) = f x acc

Ta bort en struktur ett lager åt gången

Anamorfismer , eller utvecklas , modellerar primitiv corecursion. ana bygger upp ett fixpoint lager för lager med hjälp av en kolbrafunktion (eller utvecklingsfunktion ) för att producera varje nytt lager. ana kräver en Functor instans för Functor f .

ana :: Functor f => (a -> f a) -> a -> Fix f
ana f = Fix . fmap (ana f) . f

-- list example
unfoldr :: (b -> Maybe (a, b)) -> b -> List a
unfoldr f = ana coalg
    where coalg x = case f x of
                         Nothing -> Nil_
                         Just (x, y) -> Cons_ x y

Observera att ana och cata är dubbla . Typerna och implementeringarna är spegelbilder av varandra.

Fällas ut och sedan fällas, smält

Det är vanligt att strukturera ett program som att bygga upp en datastruktur och sedan kollapsa det till ett enda värde. Detta kallas hylomorfism eller återveckling . Det är möjligt att eliminera mellanstrukturen helt och hållet för att förbättra effektiviteten.

hylo :: Functor f => (a -> f a) -> (f b -> b) -> a -> b
hylo f g = g . fmap (hylo f g) . f  -- no mention of Fix!

Härledning:

hylo f g = cata g . ana f
         = g . fmap (cata g) . unFix . Fix . fmap (ana f) . f  -- definition of cata and ana
         = g . fmap (cata g) . fmap (ana f) . f  -- unfix . Fix = id
         = g . fmap (cata g . ana f) . f  -- Functor law
         = g . fmap (hylo f g) . f  -- definition of hylo

Primitiv rekursion

Paramorfismer modellerar primitiv rekursion. Vid varje iteration av vikningen får vikningsfunktionen undertråden för vidare bearbetning.

para :: Functor f => (f (Fix f, a) -> a) -> Fix f -> a
para f = f . fmap (\x -> (x, para f x)) . unFix

Preludens tails kan modelleras som en paramorfism.

tails :: List a -> List (List a)
tails = para alg
    where alg Nil_ = cons nil nil  -- [[]]
          alg (Cons_ x (xs, xss)) = cons (cons x xs) xss  -- (x:xs):xss

Primitiv corecursion

Apomorfismer modellerar primitiv corecursion. Vid varje iteration av utspelningen kan utfoldningsfunktionen returnera antingen ett nytt frö eller en hel undertråd.

apo :: Functor f => (a -> f (Either (Fix f) a)) -> a -> Fix f
apo f = Fix . fmap (either id (apo f)) . f

Observera att apo och para är dubbla . Pilarna i typen är vända; tupeln i para är dubbel mot Either i apo , och implementeringarna är spegelbilder av varandra.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow