2

I'm reading through Real World Haskell and in my copy, on page 59, it states:

In Haskell we don't have the equivalent of null. We could use Maybe... Instead we've decided to use a no-argument Empty constructor

Then, in the next section, on Errors, there is the Haskell function:

mySecond xs = if null (tail xs)
              then error "list too short"
              else head (tail xs)

Now, I don't understand what the "null" in this function definition is referring to, since it was stated clearly that there is no equivalent to (Java's) null in Haskell.

Any help appreciated.

1
  • 2
    You can use hoogle to look up functions by name or type, then click through for docs, and then click the "source" link to look at the implementation; haskell is a pretty small language, so most things you'll come across are functions (including operators, like (>>=) and can be explored this way Commented Oct 11, 2014 at 4:23

2 Answers 2

7

null is a function which simply tests if a list is empty. It doesn't have anything to do with nullable values in other languages.

null             :: [a] -> Bool
null []          =  True
null (_:_)       =  False
Sign up to request clarification or add additional context in comments.

4 Comments

Your code and the base package pattern match the non-empty list case like this: null (_:_) = False. Is there any reason for this approach over null _ = False or is that just personal style?
@MaxGabriel, it's stylistic. They will compile to exactly the same thing.
I wouldn't be surprised if it was written null (_:_) = False to avoid warnings about overlapping pattern matches.
@JohnL: there's no warning about overlapping patterns (would be pretty annoying). The warning about overlapp-ed patterns wouldn't fire here, since the [] case is obviously a true subcase of _; you'd only get that warning when putting the _ clause first (which would indeed make the function work wrongly).
0

Not really an answer to your question, but I feel it fits here to give some technical background of what the book is talking about:

Most language implementations nowadays (C++ is the most important counterexample1) store objects not right "in place" where they are used (i.e. in the function-call stack), but in some random place on the heap. All that's stored on the stack is a pointer/reference to the actual object.

One consequence of this is that you can, with mutability, easily switch a reference to point to another object, without needing to meddle with that object itself. Also, you don't even need to have an object, instead you can consider the reference a "promise" that there will be an object by the time somebody derefers it. Now if you've learned some Haskell that will heavily remind you of lazy evaluation, and indeed it's at the ground of how lazyness is implemented. This allows not only Haskell's infinite lists etc., also you can structuce both code and data more nicely – in Haskell we call it "tying the knot", and particularly in OO languages it's quite detrimental to the way you construct objects.

Imperative languages can't do this "promise" thing nicely automatic as Haskell can: lazy evaluation without referential transparency would lead to awfully unpredictable side-effects. So when you promise a value, you need to keep track of where it'll be soonest used, and make sure you manally construct the promised object before that point. Obviously, it's a big disaster to use a reference that just points to some random place in memory (as can easily happen in C), so it's now standard to point to a conventional spot that can't be a valid memory location: this is the null pointer. That way, you get at least a predictable error message, but an error it is nevertheless; Tony Hoare therefore now calls this idea of his "billion dollar mistake".

So null references are evil, Haskell cleverly avoids them. Or does it?

Actually, it can be perfectly reasonable to not have an object at all, namely when you explicitly allow empty data structures. The classic example are linked lists, and thus Haskell has a specialised null function that checks just this: is the list empty, or is there a head I can safely refer to?
Still – this isn't really idiomatic, for Haskell has a far more general and convenient way of savely resolving such "options" scenarios: pattern matching. The idiomatic version of your example would be

mySecond' (_:x2:_) = x2
mySecond' _ = error "list too short"

Note that this is not just more consise, but also safer than your code: you check null (tail xs), but if xs itself is empty then tail will already throw an error.


1C++ certainly allows storing stuff on the heap too, but experienced programmers like to avoid it for performance reasons. On the other hand, Java stores "built-in" types (you can recognise them by lowercase names, e.g. int) on the stack, to avoid redirection cost.

2Consider the words pointer and reference as synonyms, though some languages prefer either or give them slightly different meanings.

Comments