2

I defined a function as follows in Haskell

func x | x > 0 = 4 | otherwise = error "Non positive number" 

Its inferred type is

func :: (Ord a, Num a, Num t) => a -> t 

Why can't its type be

func :: (Ord a, Num a) => a -> a 
3
  • 2
    It could be. The second type you provided is a more specific type than the inferred type, but it would be accepted. Similarly, Haskell will infer the type a -> a for the function f x = x, but you could give it a more specific type like Int -> Int, and it would be accepted. Commented Nov 24, 2016 at 9:07
  • I exptected type inference engine to derive the second type instead of first. Commented Nov 24, 2016 at 9:12
  • 1
    @user634615: why would it infer that the argument and result must be the same type, if that's not actually required for the definition? Mind, it doesn't infer that the types must be different, just that they can be different. You can still use this function in a context where the result happens to have the same type as the argument. Commented Nov 24, 2016 at 12:06

3 Answers 3

6

The type func :: (Ord a, Num a) => a -> a means that returned type should match with one you passed in. But since you are returning a constant and it doesn't depend on input, its type can be any type of class Num. Thus, compiler infers func :: (Ord a, Num a, Num t) => a -> t.

Sign up to request clarification or add additional context in comments.

Comments

4

The inferred type is correct. Let's see how it gets inferred. We will only look at the returned value first:

func x | … = 4 | … = error "…" 

The latter term, error "…" :: a, is unconstrained. However, 4 has the type Num a => a, therefore your function will have type

func :: (Num result) => ????? -> result 

Now let's have a look at x:

func x | x > 0 = … | … 

Due to the use of (>) :: Ord a => a -> a- > Bool and 0 :: Num a, x's has to be an instance of both Num and Ord. So from that point of perspective, we have

func :: (Num a, Ord a) => a -> ???? 

The important part is that 4 and x don't interact. Therefore func has

func :: (Num a, Ord a, Num result) => a -> result 

Of course, result and a could be the same type. By the way, as soon as you connect x and 4, the type will get more specific:

func x | x > 0 = 4 + x - x | … 

will have type (Num a, Ord a) => a -> a.

Comments

3

As you may or may not be aware, Haskell’s numeric literals are polymorphic. That means that a number literal, like 0 or 4, has the type Num a => a. You seem to already understand this, since the type signature you expect includes a Num constraint.

And indeed, the type signature you have provided is a valid one. If you included it, it would be accepted by the compiler, and if it’s the type you actually want, by all means include it. However, the reason it is different from the inferred type is that Haskell will attempt to infer the most general type possible, and the inferred type is more general than the one you’ve written.

The question is, why is the inferred type permitted? Well, consider this similar but distinct function:

func' x | x > 0 = "ok" | otherwise = error "Non positive number" 

This function’s type is (Ord a, Num a) => a -> String. Notably, the input of the function has absolutely no bearing on the output, aside from whether or not the result is ⊥. For this reason, the result can be absolutely anything, including a string.

However, consider yet another function, again similar but distinct:

func'' x | x > 0 = x - 1 | otherwise = error "Non positive number" 

This function must have the type you described, since it uses x to produce a new value.

However, look again at the original func definition. Note how the literal on the right hand side, the 4, does not have anything to do with x. That definition is actually quite a bit closer to func' than func'', so the numeric literal has the type Num t => t, and it never needs to be specialized. Therefore, the inferred type allows the two numeric types to be separate, and you have the more general type written in your question.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.