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?
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. –
Giusto - come ho notato "questo ha caratteristiche diverse da quella a cui stai pensando". – sclv
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 ... –