5

Is there any way to apply a function passed as an argument to two different types? As a contrived example, I can create a (Maybe Int, Maybe Bool) with the expression (Just 3, Just True), but if I try to make this behaviour more generic with the function

generic :: (a -> Maybe a) -> (Maybe Int, Maybe Bool)
generic f = (f 3, f True)

so that I might be able to do something like generic Just, the compiler complains because the type variable a is constant.

The use case of this is applying a generic function to a tree structure where each node is parametrized by a type.

dfeuer
  • 48,079
  • 5
  • 63
  • 167
igorbark
  • 95
  • 4

1 Answers1

10

This can be achieved using rank-2 polymorphism as follows:

{-# LANGUAGE Rank2Types #-}
generic :: (forall a. a -> Maybe a) -> (Maybe Int, Maybe Bool)
generic f = (f 3, f True)

Often you will need some typeclass restriction (not because the implementation of generic demands it, but because the caller cannot pass an argument that works for all types), e.g.

genericNum :: (forall a. Num a => a -> a) -> (Int, Integer)
genericNum f = (f 3, f 9)
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • 1
    I don't know how you feel about it, but I *always* turn on `ScopedTypeVariables` when I use an extension that enables `forall`; otherwise I'm likely to get confused down the road. – dfeuer Feb 05 '16 at 04:53
  • Perfect, thanks a lot! Do you know of any good resources that go through all these modern language extensions? All of the Haskell books I can find deal mostly with Haskell 98, and Haskell documentation can be pretty exhausting... – igorbark Feb 05 '16 at 21:07
  • @igorbark If you want all the extensions, there is no better source than [the horse's mouth](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghc-language-features.html). – Daniel Wagner Feb 05 '16 at 21:48
  • @igorbark: A few people seem to have gotten use of [my explanation of `RankNTypes` over here](http://stackoverflow.com/questions/12031878/what-is-the-purpose-of-rank2types/12033549#12033549). – Luis Casillas Feb 05 '16 at 22:40