How can (-) seemingly have two different types?

This was a design decision in the language. -1 is a number, but its usage in this context is not related to the function (-). (As Ackdari mentions in their answer, this usage is related to the function negate.) There are a couple compromises that allow this to work:

  1. You cannot take a right slice of the (-) operator. As a workaround, Haskell provides the subtract function.

  2. You cannot write a negative integer without parentheses unless it is at the beginning of an assignment (e.g. directly after = or ->). This produces a parse error:

    let x = 8 * -1
    

    Instead, it should be written as

    let x = 8 * (-1)
    

    However, this is fine:

    let x = -1 * 8
    

These were considered to be reasonable tradeoffs to the designers of the language.


Unary minus is special in Haskell. As stated in section 3.4 of the Report:

The special form -e denotes prefix negation, the only prefix operator in Haskell, and is syntax for negate (e). The binary - operator does not necessarily refer to the definition of - in the Prelude; it may be rebound by the module system. However, unary - will always refer to the negate function defined in the Prelude. There is no link between the local meaning of the - operator and unary negation.


The answer is already descirbed in the haskell-wiki, it states

The unary minus is syntactic sugar for the Prelude function negate

so the function (-) is always the a - b function and if you write code like let x = -y the compiler will translate it to let x = negate y.

Tags:

Haskell