I don\'t understand the role played by bottom (⊥
or _|_
) in Haskell function definitions.
The definition of zip for example describes it as \"r
I think the OP already realises this, but for the benefit of others who come here with the same confusion: zip [] _|_ = []
is not actual code!
The symbol _|_
(which is just an ascii-art rendering of the mathematical symbol ⊥
) means bottom1, but only when we're talking about Haskell. In Haskell code it does not have this meaning2.
The line zip [] _|_ = []
is a description of a property of the actual code for zip
; that if you call it with first argument []
and pass any bottom value as the second argument, the result is equal to []
. The reason they would want to say exactly this is because the technical definition of what it means for a function f
to be non-strict is when f ⊥
is not ⊥
.
But there is no role of _|_
(or ⊥
, or undefined
, or the concept of bottom at all) in defining Haskell functions (in code). It has to be impossible to pattern match on an argument to see whether it is ⊥
, for a number of reasons, and so there is no actual symbol for ⊥
in Haskell code3. zip [] _|_ = []
is documentation of a property that is a consequence of the definition of zip
, not part of its definition.
As a description of this property zip [] _ = []
is a less specific claim; it would be saying that whatever you call zip []
on, it returns []
. It amounts to exactly the same thing, since the only way zip [] ⊥
can return something non-bottom is if it never examines its second argument at all. But it's speaking less immediately to the definition of non-strict-ness.
As code forming part of the definition of the function zip [] _ = []
can't be compared and contrasted to zip [] _|_ = []
. They're not alternatives, the first is valid code, and the second is not.
1 Which is the "value" of an expression that runs forever, throws an exception, or otherwise falls to evaluate to a normal value.
2 It's not even a valid Haskell identifier, since it contains both "namey" characters (_
) and "operator" characters (|
). So it can't actually be a symbol meaning anything at all in Haskell code!
3 undefined
is often used for ⊥
, but it's more of a variable referring to a ⊥
value than the actual thing itself. Much like if you have let xs = [1, 2, 3]
you can use xs
to refer to the list [1, 2, 3]
, but you can't use it as a pattern to match some other list against; the attempted pattern match would just be treated as introducing a new variable named undefined
or xs
shadowing the old one.