An exclusive or is when you want to test for one thing or another but
not both. For example, for a word to be a valid plural, it should have an s on
the end (like cats) or it should be a collective noun (like sheep) but not both
(like sheeps). The normal or test uses the || operator
which tests for one thing or another or both. The idea here is to
provide a function which can be used instead of || to do exclusive
or testing. This name of the function is conventionally
xor, which is not very good, but it is difficult to do better.
module Xor where -- Exclusive or. xor :: a xor = undefined
To decide on the type, let's find the type of || and
copy it:
> ghci Prelude> :type ||
That doesn't work. If we look in the reference pages, we can find the type
of ||. At the same time, we might notice that when an
operator is mentioned on its own, rather than with arguments on either side, it
has brackets round it, i.e. "(||)" means "the operator
||". We can try this with ghci:
> ghci Prelude> :type (||) (||) :: Bool -> Bool -> Bool
That gives us our answer. Let's try writing down the definition of our function straight away with pattern matching (improving the comment at the same time):
module Xor where -- Find the exclusive or of two booleans. xor :: Bool -> Bool -> Bool xor false false = false xor false true = true xor true false = true xor true true = false
Unfortunately, this doesn't work:
> ghci Xor.hs
Xor.hs:5:
Conflicting definitions for `false'
In the definition of `xor'
...
The error message tells us that false is being treated as an
argument variable, when we expected it to be treated as a constant. If we look
it up in the reference pages, it has a capital letter, i.e. it is spelled
False. Let's try that change:
module Xor where -- Find the exclusive or of two booleans. xor :: Bool -> Bool -> Bool xor False False = False xor False True = True xor True False = True xor True True = False
A little testing shows that this is now OK.
> ghci Xor.hs *Xor> xor True False True
This illustrates something about pattern matching generally. Suppose we
were to define our own version of the standard not function,
called bnot to avoid a name clash:
bnot :: Bool -> Bool bnot false = True bnot true = False
GHC gives a warning but doesn't prevent compilation. But this function would
always give the answer True. This is because the name
false on the left hand side of the first statement is treated as
an argument variable name, exactly as if we had written:
bnot :: Bool -> Bool bnot b = True bnot b = False
This means that the first statement is always used, no matter what the value
of the argument, and always gives the answer True. The same
happens even if we define variables called true to act as synonyms
for the constants:
bnot :: Bool -> Bool bnot false = True bnot true = False false :: Bool false = False true :: Bool true = True
This is because local variables are always completely separate from global
ones, so the name false on the left hand side of the
first statement is a completely separate variable from the global one we have
just defined. The global variable false can be used
interchangeably with the constant False everywhere
except when pattern matching on the left hand side; (false
is not a constant; it is a variable which happens to have a constant
value).
The rule with pattern matching is that anything starting with a lower case
letter is a variable. To get matching to happen, you have to use constants or
constructors which have upper case initial letters or other special notations.
The other notations include constructor operators starting with the
: character, numerical constants, tuples, and explicit lists with
square brackets. In fact, you can use anything referred to in the reference
pages as a constant or constructor.