
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