[Haskell-cafe] Re: distinguish functions from non-functions in a class/instances

apfelmus apfelmus at quantentunnel.de
Sat Dec 8 04:51:28 EST 2007


Luke Palmer wrote:
>
> Hmm, this still seems ill-defined to me.
> 
> compose :: (Int -> Int -> Int) -> (Int -> Int) -> Int -> Int -> Int
> 
> Is a valid expression given that definition (with a,b = Int and c = Int -> Int),
> but now the arity is 4.

That's correct, the arity of a function is not well-defined due to 
polymorphism. The simplest example is probably

         id :: a -> a                -- "arity" 1
   id = ($) :: (a -> b) -> (a -> b)  -- "arity" 2

Therefore, the polymorphic expression

   wrap id

is problematic. It roughly has the type

   wrap id  ~~  [String] -> a

But it's clearly ambiguous: do we have

   wrap id (x:_)   = read x

or

   wrap id (f:x:_) = wrap ($) (f:x:_) = read f (read x)

or what? (assuming a read instance for function types)
GHCi gives it a type

   > :type wrap id
   wrap id :: (FunWrap (a -> a) y) => [String] -> y

but trying to use it like in

   > let x = wrap id ["1"] :: Int

yields lots of type errors. We have to specialize the type of  id 
before supplying it to  wrap . For example,

   wrap (id :: Int -> Int)

works just fine.


I don't like this behavior of  wrap  since it violates the nice property 
of polymorphic expressions that it's unimportant when a type variable is 
instantiated, like in

    map ((+1) :: Int -> Int) [1..5]
  = map (+1) ([1..5] :: [Int])
  = (map (+1) [1..5]) :: [Int]



Regards,
apfelmus



More information about the Haskell-Cafe mailing list