Ich lief in einer Situation, in der mein Code von der Verwendung Functor
und -ähnliche Abstraktionen profitieren würde, aber für Arten von Art (* -> *) -> *
. eine höhere kinded Funktors definieren kann mit RankNTypes
wie dieseFunktoren und Applicates für Arten von Art (* -> *) -> *
class HFunctor f where
hfmap :: (forall x. a x -> b x) -> f a -> f b
Aber je höher Art Version von Applicative
ist ein bisschen schwieriger durchgeführt werden. Dies ist das Beste, was ich tun konnte,:
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 :->
Wir brauchen die :->
Wrapper um Funktionen zu haben, mit der Art * -> *
, aber das hat uns nicht gut Anwendungskette Funktion lassen wie wir können mit <$>
und <*>
für normale Anwendungen. Ich kann mit Helfer wie
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 .)
verwalten Aber es wäre schön, einen allgemeinen Weg, um zu „heben“ Funktionen jeder Stelligkeit.
Einige einfache Beispiele, wie die obigen Beispiele verwendet werden können:
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"]
Also, meine Frage ist: Was sind die oben typeclasses genannt und werden sie bereits von einigen Bibliothek in Hackage zur Verfügung gestellt? Beim googeln kam ich mit Functor2
in linear-maps
und HFunctor
in multi-rec
, aber keiner tut genau was ich brauche.
Gibt es auch eine Möglichkeit, HApplicative
ohne die :->
Wrapper oder eine andere Möglichkeit, Funktion Heben leichter zu schreiben?
Der Unterschied ist, dass Sie Endo-Funktoren definieren, während das OP Funktoren aus einer Kategorie definiert, in der Objekte eine Art '* -> *' (vielleicht sollte dies die Kategorie von Endo-Funktoren auf Hask sein) zu Hask. –
Richtig - wie ich bemerkte "hat dies andere Eigenschaften als die, an die Sie denken". – sclv
Nur ein kleiner technischer Kommentar: 'f :: (* -> *) -> * -> *' ist kein "Funktor auf Funktoren", auch wenn 'f' ein' HFunctor' ist, weil '* -> * 'stellt nur alle Typkonstruktoren dar, sie müssen nicht selbst Funktoren sein.Zum Beispiel ist das "a: -> b" des OP im Allgemeinen kein Funktor, selbst wenn "a" und "b" sind (du willst, dass "a" ein kontravarianter Funktor ist). Ich habe fast ein paar sehr falsche Dinge geschrieben, bevor ich mich daran erinnere ... –