4

I would like to combine the various lifts into a single class

class Lift a b where
  lift :: a -> b

So that lift can be used in place of fmap, liftA2, liftA3, etc.

Now it is easy enough to write the instances for these:

instance Functor f => Lift (a -> b) (f a -> f b) where
  lift = fmap
instance Applicative f => Lift (a -> b -> c) (f a -> f b -> f c) where
  lift = liftA2
instance Applicative f => Lift (a -> b -> c -> d) (f a -> f b -> f c -> f d) where
  lift = liftA3

However for liftA2 and beyond there is an inductive property. That is we can derive a lift from smaller lifts. For example:

liftA2 f a b       = (liftA  f a)       <*> b
liftA3 f a b c     = (liftA2 f a b)     <*> c
liftA4 f a b c d   = (liftA3 f a b c)   <*> d
liftA5 f a b c d e = (liftA4 f a b c d) <*> e
...

So I would like to instead of enumerating each lift as a separate instances use induction to make all of them. However while the definition is inductive I have trouble expressing the relationship between one lift and the next algebraically. That is while I can describe it, it is not a combination of lifts and simple combinators.

Even if I rewwrite them point free we can see that each level is more complex that the last:

liftA2 = ((<*>) .) . liftA
liftA3 = (((<*>) .) .) . liftA2
liftA4 = ((((<*>) .) .) .) . liftA3
liftA5 = (((((<*>) .) .) .) .) . liftA4
...

Now I think that this could be worked around by adding a ghc natural to the class

class Lift (n :: Nat) (a :: Type) (b :: Type) | a b -> n  where
  lift :: a -> b

And then using a supporting type class to do a lot of the connective work. However this solution would be far from elegant and I view it mostly as a last resort since I would rather no bloat the class with a Nat used only for computation.

Is there a way I inductively define lift without changing the class definition like this?

Wheat Wizard
  • 3,982
  • 14
  • 34
  • Have you tried actually using your `Lift` defined the brute force way? I would expect you to have trouble... – luqui Mar 12 '20 at 04:17
  • @luqui Have trouble in what way? Aside from some initial confusion I had it seems to work perfectly. – Wheat Wizard Mar 12 '20 at 04:29
  • @SriotchilismO'Zaic You may find [this post on ‘_n_-ary functors’](http://gelisam.blogspot.com/2017/12/n-ary-functors.html) useful. – bradrn Mar 12 '20 at 04:51
  • 2
    So `lift foldr (Just (:)) (Just []) (Just [1,2,3])` works? (On my phone, otherwise I'd check it myself) – luqui Mar 12 '20 at 05:30

0 Answers0