[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.


More information about the Haskell-Cafe mailing list