In addition to providing a convenient interface for testing
code fragments, *ghci* can function as
a readily accessible desktop calculator. We can easily express any
calculator operation in *ghci* and, as
an added bonus, we can add more complex operations as we become more
familiar with Haskell. Even using the interpreter in this simple way can
help us to become more comfortable with how Haskell works.

We can immediately start entering expressions, in order to see what *ghci* will do with them. Basic arithmetic
works similarly to languages such as C and Python—we write expressions in *infix* form, where an operator
appears between its operands:

`ghci>`

4`2 + 2`

`ghci>`

3165037`31337 * 101`

`ghci>`

3.5`7.0 / 2.0`

The infix style of writing an expression
is just a convenience; we can also write an expression in
*prefix* form, where the operator precedes its arguments. To do this,
we must enclose the operator in parentheses:

`ghci>`

4`2 + 2`

`ghci>`

4`(+) 2 2`

As these expressions imply, Haskell has a notion of
integers and floating-point numbers. Integers can be arbitrarily
large. Here, `(^)`

provides
integer exponentiation:

`ghci>`

27112218957718876716220410905036741257`313 ^ 15`

Haskell presents us with one peculiarity in how we must write numbers: it’s often necessary to enclose a negative number in parentheses. This affects us as soon as we move beyond the simplest expressions.

We’ll start by writing a negative number:

`ghci>`

-3`-3`

The `-`

used in the preceding
code is a unary operator. In other words, we didn’t write the
single number “-3”; we wrote the number “3”
and applied the operator `-`

to it. The `-`

operator is Haskell’s only unary operator, and we cannot mix it with
infix operators:

`ghci>`

<interactive>:1:0: precedence parsing error cannot mix `(+)' [infixl 6] and prefix `-' [infixl 6] in the same infix expression`2 + -3`

If we want to use the unary minus near an infix operator, we must wrap the expression that it applies to in parentheses:

`ghci>`

-1`2 + (-3)`

`ghci>`

-478`3 + (-(13 * 37))`

This avoids a parsing ambiguity. When we
apply a function in Haskell, we write the name of the function,
followed by its argument—for example, `f 3`

. If we did not
need to wrap a negative number in parentheses, we would have two
profoundly different ways to read `f-3`

: it could be either
“apply the function f to the number -3,” or “subtract the number 3
from the variable f.”

*Most* of the time, we can omit
whitespace (“blank” characters such as space and tab)
from expressions, and Haskell will parse them as we intended. But not
always. Here is an expression that works:

`ghci>`

6`2*3`

And here is one that seems similar to the previous problematic negative number example, but that results in a different error message:

`ghci>`

<interactive>:1:1: Not in scope: `*-'`2*-3`

Here, the Haskell implementation is reading `*-`

as a single operator. Haskell lets us
define new operators (a subject that we will return to later), but we
haven’t defined `*-`

. Once again, a
few parentheses get us and *ghci*
looking at the expression in the same way:

`ghci>`

-6`2*(-3)`

Compared to other languages, this unusual treatment of negative numbers might seem annoying, but it represents a reasoned trade-off. Haskell lets us define new operators at any time. This is not some kind of esoteric language feature; we will see quite a few user-defined operators in the chapters ahead. The language designers chose to accept a slightly cumbersome syntax for negative numbers in exchange for this expressive power.

The values of Boolean logic in Haskell are `True`

and `False`

. The capitalization of
these names is important. The language uses C-influenced operators for
working with Boolean values: `(&&)`

is logical “and”,
and `(||)`

is logical
“or”:

`ghci>`

False`True && False`

`ghci>`

True`False || True`

While some programming languages treat
the number zero as synonymous with `False`

, Haskell does not, nor does it
consider a nonzero value to be `True`

:

`ghci>`

<interactive>:1:8: No instance for (Num Bool) arising from the literal `1' at <interactive>:1:8 Possible fix: add an instance declaration for (Num Bool) In the second argument of `(&&)', namely `1' In the expression: True && 1 In the definition of `it': it = True && 1`True && 1`

Once again, we are faced with a
substantial-looking error message. In brief, it tells us that the
Boolean type, Bool, is not a member of the family of
numeric types, `Num`

. The error message is rather long
because *ghci* is pointing out the
location of the problem and hinting at a possible change we could make
that might fix it.

Here is a more detailed breakdown of the error message:

`No instance for (Num Bool)`

Tells us that

*ghci*is trying to treat the numeric value 1 as having a Bool type, but it cannot`arising from the literal '1'`

Indicates that it was our use of the number

`1`

that caused the problem`In the definition of 'it'`

Refers to a

*ghci*shortcut that we will revisit in a few pages

We have an important point to make
here, which we will repeat throughout the early sections of this
book. If you run into problems or error messages that you do not yet
understand, *don’t panic*. Early on, all you have
to do is figure out enough to make progress on a problem. As you
acquire experience, you will find it easier to understand parts of
error messages that initially seem obscure.

The numerous error messages have a purpose: they actually help us write correct code by making us perform some amount of debugging “up front,” before we ever run a program. If you come from a background of working with more permissive languages, this may come as something of a shock. Bear with us.

Most of Haskell’s comparison operators are similar to those used in C and the many languages it has influenced:

`ghci>`

True`1 == 1`

`ghci>`

True`2 < 3`

`ghci>`

True`4 >= 3.99`

One operator that differs from its C
counterpart is “is not equal to”. In C, this is written
as `!=`

. In Haskell, we write `(/=)`

, which resembles the ≠ notation used
in mathematics:

`ghci>`

True`2 /= 3`

Also, where C-like languages often use
`!`

for logical negation, Haskell
uses the `not`

function:

`ghci>`

False`not True`

Like written algebra and other programming languages that use infix operators, Haskell has a notion of operator precedence. We can use parentheses to explicitly group parts of an expression, and precedence allows us to omit a few parentheses. For example, the multiplication operator has a higher precedence than the addition operator, so Haskell treats the following two expressions as equivalent:

`ghci>`

17`1 + (4 * 4)`

`ghci>`

17`1 + 4 * 4`

Haskell assigns numeric precedence values
to operators, with 1 being the lowest precedence and 9 the highest. A
higher-precedence operator is applied before a lower-precedence operator. We can use *ghci* to inspect the precedence levels of
individual operators, using *ghci*’s
*:info* command:

`ghci>`

class (Eq a, Show a) => Num a where (+) :: a -> a -> a ... -- Defined in GHC.Num infixl 6 +`:info (+)`

`ghci>`

class (Eq a, Show a) => Num a where ... (*) :: a -> a -> a ... -- Defined in GHC.Num infixl 7 *`:info (*)`

The information we seek is in the line
`infixl 6 +`

, which indicates that
the `(+)`

operator has a precedence
of 6. (We will explain the other output in a later chapter.) `infixl 7 *`

tells us that the `(*)`

operator has a precedence of 7. Since
`(*)`

has a higher precedence than
`(+)`

, we can now see why ```
1 +
4 * 4
```

is evaluated as `1 + (4 * 4)`

, and not
`(1 + 4) * 4`

.

Haskell also defines
*associativity* of operators. This determines
whether an expression containing multiple uses of an operator is
evaluated from left to right or right to left. The `(+)`

and `(*)`

operators are left associative, which
is represented as `infixl`

in the preceding *ghci* output. A right associative operator is
displayed with `infixr`

:

`ghci>`

(^) :: (Num a, Integral b) => a -> b -> a -- Defined in GHC.Real infixr 8 ^`:info (^)`

The combination of precedence and
associativity rules are usually referred to as
*fixity* rules.

Haskell’s `Prelude`

, the
standard library we mentioned earlier, defines at least one well-known
mathematical constant for us:

`ghci>`

3.141592653589793`pi`

But its coverage of mathematical constants is not
comprehensive, as we can quickly see. Let us look for Euler’s number,
`e`

:

`ghci>`

<interactive>:1:0: Not in scope: `e'`e`

Oh well. We have to define it ourselves.

If the ```
not in
scope
```

error message seems a little daunting, do not worry.
All it means is that there is no variable defined with the name
`e`

.

Using *ghci*’s
`let`

construct, we can make a temporary definition of `e`

ourselves:

`ghci>`

`let e = exp 1`

This is an application of the exponential
function, `exp`

, and our first
example of applying a function in Haskell. While languages such as
Python require parentheses around the arguments to a function, Haskell
does not.

With `e`

defined, we can
now use it in arithmetic expressions. The `(^)`

exponentiation operator that we introduced earlier can only raise a number to
an integer power. To use a floating-point number as the exponent, we
use the`(**)`

exponentiation
operator:

`ghci>`

19.99909997918947`(e ** pi) - pi`

The syntax for `let`

that *ghci* accepts is not the same as we would
use at the “top level” of a normal Haskell program. We
will see the normal syntax in Introducing Local Variables.

It is sometimes better to leave at least some parentheses in place, even when Haskell allows us to omit them. Their presence can help future readers (including ourselves) to understand what we intended.

Even more importantly, complex expressions that rely completely on operator precedence are notorious sources of bugs. A compiler and a human can easily end up with different notions of what even a short, parenthesis-free expression is supposed to do.

There is no need to remember all of the precedence and associativity rules numbers: it is simpler to add parentheses if you are unsure.

Start Free Trial

No credit card required