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

Dan Weston westondan at imageworks.com
Mon Dec 10 14:33:20 EST 2007


Questioning apfelmus definitely gives me pause, but...

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

I agree with the arities given above (but without quotes) and see no 
ill-definedness to arity.

But these are two different classes of functions. There are arguments of 
the first function that cannot be applied to the second (e.g. 5). The 
fact that the two have different type signatures shows that Haskell can 
distinguish them (e.g. in the instantiation of a type class).

The difficulties of Haskell's type system in the presence/intersection 
of ad hoc/parametric polymorphism is an orthogonal issue. I think that 
every function application must have a unique monomorphic type at the 
call site of the "arity" function (assisted or not by type annotation), 
and this type is known to converge in a Template Haskell construction.

 > We have to specialize the type of  id before
 > supplying it to  wrap . For example,
 >
 >   wrap (id :: Int -> Int)
 >
 > works just fine.

The necessity of type annotation/restriction is an orthogonal issue to 
the above.

Am I missing something more fundamental?

apfelmus wrote:
> 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
> 
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
> 
> 




More information about the Haskell-Cafe mailing list