[Haskell-cafe] how do I avoid excessive constructor application?

Ben Lippmeier Ben.Lippmeier at anu.edu.au
Tue Mar 1 22:40:48 EST 2005


S. Alexander Jacobson wrote:
> 
> For some reason, these two functions have different types.
> 
>   fun1 f (Left x)= Left (f x)
>   fun1 _ r@(Right x) = Right x
> 
>   fun2 f (Left x) = Left (f x)
>   fun2 _ r = r

fun1 :: forall a a1 b . (a -> a1) -> Either a b -> Either a1 b
fun2 :: forall a b    . (a -> a)  -> Either a b -> Either a  b

fun1 is indeed more general than fun2 because there is no way for an x 
inside a (Left x) from the LHS of the function to be returned as part of 
the result.

---
You can play games with the type checker to force them to have the same 
type without changing the "meaning" of your function.

fun1' f (Left x)    = if True then Left (f x) else Left x
fun1' _ r@(Right x) = Right x

 > :type fun1'
fun1' :: forall b a. (a -> a) -> Either a b -> Either a b

This assumes that the compiler doesn't perform an "optimisation" that 
throws away the second alternative of the if statement before it does 
type checking.

---
A more sensible way is to add an explicit type signature to force it to 
have a less general type than what was inferred.

fun1 :: forall a b . (a -> a) -> Either a b -> Either a b

----
> Is there a way to rewrite fun2 so that f has type (a->b)?
Delete the second line, but then you have a different function.


> In the general case, it seems wasteful to have to destruct and construct 
> values just for type checking reasons, especially if your type has many 
> more constructors than (Either a b).

Standard type inference always returns the *most general* type, and it 
is never "wrong" (unless there's a bug in the compiler).

If you actually want a less general type for one of your functions 
(maybe the more general one isn't useful in your particular program) 
then add a type signature to constrain it.

Ben.


More information about the Haskell-Cafe mailing list