What is the type of (1 2) in Haskell?
Asked Answered
D

2

6

I was playing around with hugs today and got stuck at a very simple question:

λ 1 1
:: (Num a, Num (a -> t)) => t

What would that type be? I am having trouble to read this.

And if it has a type, why? I would guess that the expression 1 1 is ill-formed and thus type-checking fails, which is supported by the Haskell compiler.

Dopey answered 13/10, 2015 at 12:6 Comment(0)
L
12

No it is not ill-formed. The type is strange and there probably cannot be any meaningful values for which it makes sense but it's still allowed.

Keep in mind that literals are overloaded. 1 is not an integer. It's anything of type Num. Functions are not excluded from this. There is no rule saying a -> t cannot be " a number" (i.e. an instance of Num).

For example you could have an instance declaration like:

instance Num a => Num (a -> b) where
    fromInteger x = undefined
    [...]

now 1 1 would simply be equal undefined. Not very useful but still valid.

You can have useful definitions of Num for functions. For example, from the wiki

instance Num b => Num (a -> b) where
     negate      = fmap negate
      (+)         = liftA2 (+)
      (*)         = liftA2 (*)
      fromInteger = pure . fromInteger
      abs         = fmap abs
      signum      = fmap signum

With this you can write things like:

f + g

where f and g are functions returning numbers.

Using the above instance declaration 1 2 would be equal to 1. Basically a literal used as a function with the above instance is equal to const <that-literal>.

Lastly answered 13/10, 2015 at 12:17 Comment(4)
By the way, are there any practical examples of an expression such as 1 2 or True "hello" or "hello" [1,2,3] etc being useful? DSLs I guess?Kozloski
True is not overloaded – it is an actual constructor of the data Bool = False | True data typeAerobatics
@ErikAllik I have never seen this used in this way. It may be possible but AFAIK isn't used.Lastly
Small but important nitpick of "It's anything of type Num.": Num is not a type. Num is a typeclass.Knockabout
R
5

In Haskell, 1 doesn't have a fixed type. It is "any numeric type". More exactly, any type that implements the Num class.

In particular, it is technically valid for a function type to be an instance of Num. Nobody would ever do that, but technically it's possible.

So the compiler is assuming that the first 1 is some sort of numeric function type, and then the second 1 is any other number type (maybe the same type, maybe a different one). If we change the expression to, say, 3 6, then the compiler is assuming

3 :: Num (x -> y) => x -> y
6 :: Num x => x
3 6 :: (Num (x -> y), Num x) => y
Richert answered 13/10, 2015 at 12:15 Comment(1)
Well it causes a bit of a mess when you make functions an instance of Num, but I wouldn't say nobody would ever do that. It is useful in the same sense that a Monoid instance of functions is useful: you can for example write something like (+5) * (+3) and get a new function that does \x -> (x + 5) * (x + 3), I think that is pretty cool. See also here.Thermos

© 2022 - 2024 — McMap. All rights reserved.