
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.