Functors and Applicatives for types of kind (* -> *) -> *

你离开我真会死。 提交于 2019-12-12 09:31:45

问题


I ran into a situation where my code would benefit from using Functor and Applicative -like abstractions, but for types of kind (* -> *) -> *. Defining a higher-kinded functor can be done with RankNTypes like this

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

But the higher kind version of Applicative is a bit trickier. This is the best I could come up with:

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 :->

We need the :-> wrapper type in order to have functions with the kind * -> *, but this doesn't let us nicely chain function application like we can with <$> and <*> for normal Applicatives. I can manage with helper such as

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 .)

But it would be nice to have a general way to "lift" functions of any arity.

Some simple examples how the above instances can be used:

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"]

So, my question is: what are the above typeclasses called and are they already provided by some library in hackage? By googling I came up with Functor2 in linear-maps and HFunctorin multi-rec but neither does exactly what I need.

Also, is there some way to write HApplicative without the :-> wrapper or some other way to make function lifting easier?


回答1:


The HFunctor I tend to think of is (* -> *) -> * -> * -- i.e. a legitimate functor on functors. This has different characteristics than the one you're thinking of.

Here's how to define it, as well as the "monoidal" version of an applicative on it.

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))

I'll try to update later with some ideas about what this is and how to use it.

This isn't exactly what you're asking for, I realize, but I was inspired to try it out by your post.

I'd be interested in your specific use case as well.

To your two specific questions A) The HFunctor you describe has been described before on various occasions, I think by Gibbons in particular, but I don't know of it packaged up. I certainly haven't seen the Applicative before. B) I think you're stuck with the wrapper because we can't partially apply type synonyms.



来源:https://stackoverflow.com/questions/18052158/functors-and-applicatives-for-types-of-kind

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!