2013-08-05 7 views
20

Ho avuto una situazione in cui il mio codice avrebbe beneficiato dell'uso delle astrazioni Functor e Applicative -like, ma per tipi di tipo (* -> *) -> *. Definizione di un funtore superiore kinded può essere fatto con RankNTypes come questoFunctional and Applicatives per tipi di tipo (* -> *) -> *

class HFunctor f where 
    hfmap :: (forall x. a x -> b x) -> f a -> f b 

Ma la versione più alta di tipo Applicative è un po 'più complicato. Questo è il meglio che ho potuto venire con:

class HFunctor f => HApplicative f where 
    hpure :: (forall x. a x) -> f a 
    (<**>) :: f (a :-> b) -> f a -> f b 

newtype (:->) a b x = HFunc (a x -> b x) 

infixr 5 :-> 

Abbiamo bisogno del tipo :-> involucro in modo da avere funzioni con il genere * -> *, ma questo non ci lasciamo ben applicazione funzione catena come possiamo con <$> e <*> per i normali applicativi. Posso gestire con helper come

liftHA2 :: HApplicative f => (forall x. a x -> b x -> c x) -> f a -> f b -> f c 
liftHA2 f fa fb = hpure (fun2 f) <**> fa <**> fb where 
    fun2 = HFunc . (HFunc .) 

ma sarebbe bello avere un modo generale di funzioni "lift" di qualsiasi arity.

Alcuni semplici esempi di come le istanze di cui sopra possono essere utilizzati:

data Example f = Example (f Int) (f String) 

instance HFunctor Example where 
    hfmap f (Example i s) = Example (f i) (f s) 

instance HApplicative Example where 
    hpure a = Example a a 
    Example (HFunc fi) (HFunc fs) <**> Example i s = Example (fi i) (fs s) 

e :: Example [] 
e = Example [1,2,3] ["foo", "bar"] 

e' :: Example ((,) Int) 
e' = hfmap (length &&& head) e -- Example (3,1) (2, "foo") 

e'' :: Example [] 
e'' = liftHA2 (++) e e -- Example [1,2,3,1,2,3] ["foo", "bar", "foo", "bar"] 

Quindi, la mia domanda è: quali sono le typeclasses sopra chiamati e sono già forniti da qualche libreria in hackage? Con googling mi si avvicinò con Functor2 in linear-maps e HFunctor in multi-rec ma nessuno fa esattamente quello che mi serve.

Inoltre, c'è qualche modo per scrivere HApplicative senza :-> involucro o qualche altro modo per rendere più facile la funzione di sollevamento?

risposta

2

Il HFunctor tendo a pensare è (* -> *) -> * -> * - vale a dire un funtore legittimo funtori. Questo ha caratteristiche diverse da quella a cui stai pensando.

Ecco come definirlo, così come la versione "monoidale" di un applicativo su di esso.

type Nat f g = forall a. f a -> g a 

class HFunctor (f :: (* -> *) -> * -> *) where 
    hfmap :: (Nat g h) -> Nat (f g) (f h) 

data Prod f g a = Prod (f a) (g a) 

class HFunctor f => HApplicative f where 
    hpure :: Nat g (f g) 
    htensor :: Nat (Prod (f g) (f h)) (f (Prod g h)) 

Cercherò di aggiornare in seguito con alcune idee su cosa sia e come usarlo.

Questo non è esattamente quello che stai chiedendo, mi rendo conto, ma mi è stato ispirato per provarlo dal tuo post.

Sarei interessato nel tuo caso specifico uso pure.

Per le tue due domande specifiche A) L'HFunctor che descrivi è stato descritto prima in varie occasioni, penso in particolare da Gibbons, ma non ne sono a conoscenza. Non ho certamente visto la Applicativa prima. B) Penso che tu sia bloccato con il wrapper perché non possiamo applicare parzialmente i sinonimi di tipo.

+0

la differenza è che si stanno definendo endo-functors, mentre l'OP sta definendo i funtori da qualche categoria in cui gli oggetti hanno tipo '* -> *' (forse questa dovrebbe essere la categoria degli endo functor su Hask) a Hask. –

+0

Giusto - come ho notato "questo ha caratteristiche diverse da quella a cui stai pensando". – sclv

+0

Solo un piccolo commento tecnico: 'f :: (* -> *) -> * -> *' non è un "functor on functors", anche se 'f' è un' HFunctor', perché '* -> * 'rappresenta solo tutti i costruttori di tipi, non devono necessariamente essere i funtori stessi.Ad esempio, l'OP 'a: -> b' non è un functor in generale, anche se' a' e 'b' sono (si vorrebbe' a' essere un functor controvariante). Ho quasi scritto alcune cose molto sbagliate prima di ricordare questo ... –