2015-03-12 7 views
9

Sto giocando con la formulazione di Applicative in termini di pure e liftA2 (in modo che (<*>) = liftA2 id diventi un combinatore derivato).Quali sono le leggi del functor applicativo in termini di puro e liftA2?

Posso pensare a un gruppo di leggi candidate, ma non sono sicuro di quale sarebbe il set minimo.

  1. f <$> pure x = pure (f x)
  2. f <$> liftA2 g x y = liftA2 ((f .) . g) x y
  3. liftA2 f (pure x) y = f x <$> y
  4. liftA2 f x (pure y) = liftA2 (flip f) (pure y) x
  5. liftA2 f (g <$> x) (h <$> y) = liftA2 (\x y -> f (g x) (h y)) x y
  6. ...
+0

'liftA2' è definito in termini di' <$> 'e' <*> ', non so perché dovresti invece definire' <*> 'in termini di' liftA2'. – bheklilr

+0

Sì, ma mi piacerebbe fare qualcosa di simile a quello che fa EZ Yang nel suo post di confronto tra Applicativo e Monoidale: http://blog.ezyang.com/2012/08/applicative-functors/ –

+2

'Applicativo' con' puro 'e' liftA2' è la stessa di questa classe ['Monoidal'] (http://www.haskellforall.com/2014/07/equational-reasoning-at-scale.html) che ha un elenco di leggi. Per passare da 'Monoidal' a' Applicativo' con 'pure' e' liftA2' si [sostituisci tipi e costruttori espliciti nell'interfaccia con elementi che possono essere passati al tipo o al costruttore per recuperare l'interfaccia originale] (http: // stackoverflow.com/a/27262462/414413). – Cirdec

risposta

7

Sulla base di McBride e Paterson di laws for Monoidal (sezione 7) Mi piacerebbe SUG Gestire le seguenti leggi per liftA2 e pure.

sinistra e l'identità destra

liftA2 (\_ y -> y) (pure x) fy  = fy 
liftA2 (\x _ -> x) fx  (pure y) = fx 

associatività

liftA2 id   (liftA2 (\x y z -> f x y z) fx fy) fz = 
liftA2 (flip id) fx (liftA2 (\y z x -> f x y z) fy fz) 

naturalità

liftA2 (\x y -> o (f x) (g y)) fx fy = liftA2 o (fmap f fx) (fmap g fy) 

Non è immediatamente evidente che questi sono sufficienti a coprire la relazione tra fmap e Applicative s' pure e liftA2. Vediamo se possiamo dimostrare dalle leggi di cui sopra che

fmap f fx = liftA2 id (pure f) fx 

Inizieremo lavorando su fmap f fx. Tutti i seguenti sono equivalenti.

fmap f fx 
liftA2 (\x _ -> x) (fmap f fx) (  pure y)  -- by right identity 
liftA2 (\x _ -> x) (fmap f fx) ( id (pure y))  -- id x = x by definition 
liftA2 (\x _ -> x) (fmap f fx) (fmap id (pure y))  -- fmap id = id (Functor law) 
liftA2 (\x y -> (\x _ -> x) (f x) (id y)) fx (pure y) -- by naturality 
liftA2 (\x _ -> f x     ) fx (pure y) -- apply constant function 

A questo punto abbiamo scritto fmap in termini di liftA2, pure e qualsiasi y; fmap è interamente determinato dalle leggi di cui sopra. Il resto della prova non ancora provata è lasciato dall'autore irresoluto come esercizio per il lettore determinato.

+0

Interessante, che la legge di identità possa essere riscritta in questo modo: 'liftA2 const fx (puro y) == const fx (puro y)' e 'flip (liftA2 (flip const)) fx (pure y) == const fx (pure y) '(o' liftA2 (flip const) (pure x) fy == flip const (pure x) fy'), che forse aggiunge un angolo interessante. –

0

Per il libro online, Learn You A Haskell:Functors, Applicative Functors and Monoids, le leggi del Codice di applicazione sono in sequenza ma riorganizzate per motivi di formattazione; tuttavia, sto facendo questo modificabile messaggio comunità dal momento che sarebbe utile se qualcuno potesse incorporare derivazioni:

identity]    v = pure id <*> v 
homomorphism]  pure (f x) = pure f <*> pure x 
interchange] u <*> pure y = pure ($ y) <*> u 
composition] u <*> (v <*> w) = pure (.) <*> u <*> v <*> w 

Nota:

function composition] (.) = (a->b) -> (b->c) -> (a->c) 
application operator] $ = (a->b) -> a -> b 

Found a treatment on Reddit

+1

Dovrebbe '(.)' Non essere '(a-> b) -> (b-> c) -> (a-> c)'? – Zaaier

Problemi correlati