1

Is it possible to write a function for generic types (in this case applicatives) without making assumptions about the name of type constructors?

I can write the following:

f :: Maybe a -> Maybe a
f (Just a) = (Just a)

That one works on Maybes and only instances with the Just constructor.

But say I had different types that have a value constructor that had the same name as the type constructor:

data T a = T a

instance Functor T where
  fmap f (T a) = T (f a)

instance Applicative T where
  pure = T
  (T f) <*>  (T something) = fmap f (T something)




data U a = U a

instance Functor U where
  fmap f (U a) = U (f a)

instance Applicative U where
  pure = U
  (U f) <*>  (U something) = fmap f (U something)

In this case T and U are isomorphic, but maybe they also would have constructors that are special to either one in a real example... does not matter here.

Now what if wanted a function that operates both on T and U... I could write the function two times, like so:

gt :: T a -> T a
gt (T x) =  T x

gu :: U a -> U a
gu (U x) =  U x

Is there also a way to make a template for this function like this?

g :: (Applicative f) => f a -> f a
g (f x) = f x

That will give me a syntax error for some reason, even though it has the same structure as gt and gu.

If there is no way to do that then why not?

lo tolmencre
  • 3,804
  • 3
  • 30
  • 60
  • 4
    (1) If you have an use case that goes beyond the example code you posted, you likely want to tell us more about it. As it stands, there are lots of things that *might* do what you want, and it's hard to tell which relevant: a preexisting class, a class that you'd define yourself, newtype juggling (`coerce`, `Control.Lens.Wrapped`, etc.), generics, etc. (2) "only instances with the `Just` constructor" -- Terminology nitpick: you mean "values", rather than "instances". – duplode Feb 20 '18 at 03:32
  • 1
    (3) "without making assumptions about the name of type constructors" -- I'd say that's more a *choice* than an assumption. If you cease from making it explicitly, you might end up needing other assumptions (e.g. "there is a constructor that has the same name as the type", "the constructor has the fields I expect it to have", "there aren't other constructors, so I don't need to worry about handling them"). (4) "That will give me a syntax error for some reason" -- the `f` from the signature is unrelated to the one of the definition. You might be mixing up type level things with value level ones. – duplode Feb 20 '18 at 03:33
  • 2
    That would be rather weird for several reasons: since (a) a type can have *multiple* constructors, and a constructor itself thus carries semantics, (b) some constructors have more parameters than others (c) it would also conflict with "*make explicit with what needs to be explicit*". – Willem Van Onsem Feb 20 '18 at 07:22
  • 5
    If this were somehow possible, I think you need your own custom typeclass. Otherwise, what could the type of `g` be? The one you gave `(Applicative f) => f a -> f a` is too general, since it allows `f ~ (->) b`, but `b -> a` has no constructors. Hence, we need a stronger constraint. With a custom typeclass, one could just move everything in the instances, and avoid to match on `f x` which is not allowed. – chi Feb 20 '18 at 09:05
  • @chi What does `~` mean here? – lo tolmencre Feb 20 '18 at 23:12

0 Answers0