Forse l'esempio canonico è dato dai vettori.
data Nat = Z | S Nat deriving (Show, Eq, Ord)
data Vec :: Nat -> * -> * where
V0 :: Vec Z x
(:>) :: x -> Vec n x -> Vec (S n) x
Possiamo applicarli con un piccolo sforzo, prima definendo singleton, quindi avvolgendoli in una classe.
data Natty :: Nat -> * where
Zy :: Natty Z
Sy :: Natty n -> Natty (S n)
class NATTY (n :: Nat) where
natty :: Natty n
instance NATTY Z where
natty = Zy
instance NATTY n => NATTY (S n) where
natty = Sy natty
Ora noi possiamo sviluppare la struttura di Applicative
instance NATTY n => Applicative (Vec n) where
pure = vcopies natty
(<*>) = vapp
vcopies :: forall n x. Natty n -> x -> Vec n x
vcopies Zy x = V0
vcopies (Sy n) x = x :> vcopies n x
vapp :: forall n s t. Vec n (s -> t) -> Vec n s -> Vec n t
vapp V0 V0 = V0
vapp (f :> fs) (s :> ss) = f s :> vapp fs ss
Tralascio l'istanza Functor
(che dovrebbe essere estratto tramite fmapDefault
dall'istanza Traversable
).
Ora, c'è un'istanza Monad
corrispondente a questo Applicative
, ma che cos'è? Pensiero diagonale! Questo è ciò che è richiesto! Un vettore può essere visto come la tabulazione di una funzione da un dominio finito, quindi lo Applicative
è solo una tabella dei combinatori K e S e lo Monad
ha un comportamento simile a Reader
.
vtail :: forall n x. Vec (S n) x -> Vec n x
vtail (x :> xs) = xs
vjoin :: forall n x. Natty n -> Vec n (Vec n x) -> Vec n x
vjoin Zy _ = V0
vjoin (Sy n) ((x :> _) :> xxss) = x :> vjoin n (fmap vtail xxss)
instance NATTY n => Monad (Vec n) where
return = vcopies natty
xs >>= f = vjoin natty (fmap f xs)
si potrebbe risparmiare un po 'definendo >>=
più direttamente, ma in qualsiasi modo si taglia, il comportamento monadica crea thunk inutili per i calcoli off-diagonale. La pigrizia potrebbe salvarci dal rallentamento di un fattore di armageddon, ma il comportamento di zipping dello <*>
è destinato ad essere almeno un po 'più economico rispetto alla diagonale di una matrice.
si potrebbe essere interrotto in [Il progetto Haxl] (https://github.com/meiersi/HaskellerZ/blob/master/meetups/20130829-FPAfternoon_The_Haxl_Project_at_Facebook/The%20Haxl%20Project%20at%20Facebook.pdf?raw=true) su Facebook. Utilizza un applicativo che consente di parallelizzare i calcoli. Non è possibile parallelizzare i calcoli usando l'interfaccia monadica. – bennofs