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.

Jens
  • 9,058
  • 2
  • 26
  • 43

2 Answers2

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

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
  • 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? – Erik Kaplun Oct 13 '15 at 13:07
  • 1
    `True` is not overloaded – it is an actual constructor of the `data Bool = False | True` data type – Fraser Oct 13 '15 at 13:15
  • @ErikAllik I have never seen this used in this way. It may be possible but AFAIK isn't used. – Bakuriu Oct 13 '15 at 13:16
  • Small but important nitpick of "It's anything of type `Num`.": `Num` is not a type. `Num` is a *typeclass*. – Rein Henrichs Oct 13 '15 at 15:50
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
MathematicalOrchid
  • 61,854
  • 19
  • 123
  • 220
  • 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](https://wiki.haskell.org/Num_instance_for_functions). – Sam van Herwaarden Oct 13 '15 at 12:19