Zoeken…


Invoering

Applicative is de klasse van typen f :: * -> * waarmee een opgeheven functie kan worden toegepast op een structuur waarbij de functie ook in die structuur is ingebed.

Opmerkingen

Definitie

class Functor f => Applicative f where
    pure  :: a -> f a
    (<*>) :: f (a -> b) -> f a -> f b

Let op de Functor op f . De pure functie retourneert zijn argument ingebed in de Applicative structuur. De infix-functie <*> (uitgesproken als "toepassen") lijkt erg op fmap behalve met de functie ingebed in de Applicative structuur.

Een correct exemplaar van Applicative moet voldoen aan de applicatieve wetgeving , hoewel deze niet worden afgedwongen door de compiler:

pure id <*> a = a                              -- identity
pure (.) <*> a <*> b <*> c = a <*> (b <*> c)   -- composition
pure f <*> pure a = pure (f a)                 -- homomorphism
a <*> pure b = pure ($ b) <*> a                -- interchange

Alternatieve definitie

Aangezien elke Applicative Functor een Functor is , kan er altijd fmap op worden gebruikt; de essentie van Applicative is dus het koppelen van gedragen inhoud, evenals de mogelijkheid om het te maken:

class Functor f => PairingFunctor f where
  funit :: f ()                  -- create a context, carrying nothing of import
  fpair :: (f a,f b) -> f (a,b)  -- collapse a pair of contexts into a pair-carrying context

Deze klasse is isomorf voor Applicative .

pure a = const a <$> funit = a <$ funit  

fa <*> fb = (\(a,b) -> a b) <$> fpair (fa, fb) = uncurry ($) <$> fpair (fa, fb)

Omgekeerd,

funit = pure ()

fpair (fa, fb) = (,) <$> fa <*> fb

Veel voorkomende gevallen van toepassing

Kan zijn

Maybe is een applicatief functor die een mogelijk-afwezige waarde bevat.

instance Applicative Maybe where
    pure = Just
    
    Just f <*> Just x = Just $ f x
    _ <*> _ = Nothing

pure tilt de gegeven waarde in Maybe door Just te passen. De functie (<*>) past een functie gewikkeld in een Maybe op een waarde in een Maybe . Als zowel de functie als de waarde aanwezig zijn (geconstrueerd met Just ), wordt de functie op de waarde toegepast en wordt het samengevoegde resultaat geretourneerd. Als een van beide ontbreekt, kan de berekening niet doorgaan en wordt er Nothing geretourneerd.

lijsten

Een manier voor lijsten om te passen bij de typeaanduiding <*> :: [a -> b] -> [a] -> [b] is om het Cartesiaanse product van de twee lijsten te nemen, waarbij elk element van de eerste lijst aan elk wordt gekoppeld element van de tweede:

fs <*> xs = [f x | f <- fs, x <- xs]
         -- = do { f <- fs; x <- xs; return (f x) }

pure x = [x]

Dit wordt meestal geïnterpreteerd als het emuleren van niet-determinisme, met een lijst met waarden die staat voor een niet-deterministische waarde waarvan de mogelijke waarden variëren over die lijst; dus een combinatie van twee niet-deterministische waarden varieert over alle mogelijke combinaties van de waarden in de twee lijsten:

ghci> [(+1),(+2)] <*> [3,30,300]
[4,31,301,5,32,302]

Oneindige streams en zip-lijsten

Er is een klasse van Applicative 's die hun twee ingangen samen "zipen". Een eenvoudig voorbeeld is dat van oneindige streams:

data Stream a = Stream { headS :: a, tailS :: Stream a }

De Applicative instantie van Stream past een stroom van functies puntsgewijs toe op een stroom argumenten, waarbij de waarden in de twee stromen per positie worden gekoppeld. pure retourneert een constante stroom - een oneindige lijst met één vaste waarde:

instance Applicative Stream where
    pure x = let s = Stream x s in s
    Stream f fs <*> Stream x xs = Stream (f x) (fs <*> xs)

Lijsten laten ook een "zippy" Applicative instantie toe, waarvoor het ZipList type ZipList bestaat:

newtype ZipList a = ZipList { getZipList :: [a] }

instance Applicative ZipList where
    ZipList xs <*> ZipList ys = ZipList $ zipWith ($) xs ys

Aangezien zip zijn resultaat bijsnijdt volgens de kortste invoer, is de enige implementatie van pure die voldoet aan de Applicative wetgeving er een die een oneindige lijst retourneert:

    pure a = ZipList (repeat a)   -- ZipList (fix (a:)) = ZipList [a,a,a,a,...

Bijvoorbeeld:

ghci> getZipList $ ZipList [(+1),(+2)] <*> ZipList [3,30,300]
[4,32]

De twee mogelijkheden herinneren ons aan het buitenste en het binnenste product, vergelijkbaar met het vermenigvuldigen van een matrix met 1 kolom ( nx 1 ) met een matrix met 1 rij ( 1 xm ) in het eerste geval, waardoor de nxm matrix wordt verkregen (maar afgeplat ); of vermenigvuldigen van een 1-rij en een 1-kolom matrices (maar zonder de samenvatting) in het tweede geval.

functies

Wanneer gespecialiseerd in functies (->) r , komen de typeaanduidingen van pure en <*> overeen met die van respectievelijk de K en S combinators:

pure :: a -> (r -> a)
<*> :: (r -> (a -> b)) -> (r -> a) -> (r -> b)

pure moet const zijn en <*> neemt een paar functies en past ze elk toe op een vast argument, waarbij de twee resultaten worden toegepast:

instance Applicative ((->) r) where
    pure = const
    f <*> g = \x -> f x (g x)

Functies zijn de prototypische "zippy" applicatie. Omdat oneindige stromen bijvoorbeeld isomorf zijn voor (->) Nat , ...

-- | Index into a stream
to :: Stream a -> (Nat -> a)
to (Stream x xs) Zero = x
to (Stream x xs) (Suc n) = to xs n

-- | List all the return values of the function in order
from :: (Nat -> a) -> Stream a
from f = from' Zero
    where from' n = Stream (f n) (from' (Suc n))

... door streams op een hogere volgorde weer te geven, wordt de zippy Applicative instantie automatisch geproduceerd.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow