Reputation: 3929
In Java, with a little exception, null
is of every type. Is there a corresponding object like that in Haskell?
Upvotes: 2
Views: 347
Reputation: 6515
I disagree with almost every other answer to this question.
loop :: a
loop = loop
does not define a value of any type. It does not even define a value.
loop :: a
is a promise to return a value of type a
.
loop = loop
is an endless loop, so the promise is broken. Since loop
never returns at all, it follows that it never returns a value of type a
. So no, even technically, there is no null
value in Haskell.
The closest thing to null
is to use Maybe
. With Maybe
you have Nothing
, and this is used in many contexts. It is also much more explicit.
A similar argument can be used for undefined
. When you use undefined
in a non-strict setting, you just have a thunk that will throw an error as soon as it is evaluated. But it will never give you a value of the promised type.
Haskell has a bottom type because it is unavoidable. Due to the halting problem, you can never prove that a function will actually return at all, so it is always possible to break promises. Just because someone promises to give you 100$, it does not mean that you will actually get it. He can always say "I didn't specify when you will get the money" or just refuse to keep the promise. The promise doesn't even prove that he has the money or that he would be able to provide it when asked about it.
An example from the Apple-world..
Objective C had a null
value and it has been called nil
. The newer Swift language switched to an Optional
type, where Optional<a>
can be abbreviated to a?
. It behaves exactly like Haskells Maybe
monad. Why did they do this? Maybe because of Tony Hoare's apology. Maybe because Haskell was one of Swifts role-models.
Upvotes: 0
Reputation: 61
Bottom inhabits every type in Haskell. It can be written explicitly as undefined
in GHC.
Upvotes: 0
Reputation: 71535
Technically yes, as Daniel Wagner's answer states.
However I would argue that "a value that can be used for every type" and "a value like Java's null
" are actually very different requirements. Haskell does not have the latter. I think this is a good thing (as does Tony Hoare, who famously called his invention of null-references a billion-dollar mistake).
Java-like null
has no properties except that you can check whether a given reference is equal to it. Anything else you ask of it will blow up at runtime.
Haskell undefined
(or error "my bad"
, or let x = x in x
, or fromJust Nothing
, or any of the infinite ways of getting at it) has no properties at all. Anything you ask of it will blow up at runtime, including whether any given value is equal to it.
This is a crucial distinction because it makes it near-useless as a "missing" value. It's not possible to do the equivalent of if (thing == null) { do_stuff_without_thing(); } else { do_stuff_with(thing); }
using undefined
in place of null
in Haskell. The only code that can safely handle a possibly-undefined value is code that just never inspects that value at all, and so you can only safely pass undefined
to other code when you know that it won't be used in any way1.
Since we can't do "null pointer checks", in Haskell code we almost always use some type T
(for arguments, variables, and return types) when we mean there will be a value of type T
, and we use Maybe T
2 when we mean that there may or may not be a value of type T
.
So Haskellers use Nothing
roughly where Java programmers would use null
, but Nothing
is in practice very different from Haskell's version of a value that is of every type. Nothing
can't be used on every type, only "Maybe
types" - but there is a "Maybe
version" of every type. The type distinction between T
and Maybe T
means that it's clear from the type whether you can omit a value, when you need to handle the possible absence of a value3, etc. In Java you're relying on the documentation being correct (and present) to get that knowledge.
1 Laziness does mean that the "won't be inspected at all" situation can come up a lot more than it would in a strict language like Java, so sub-expressions that may-or-may-not be the bottom value are not that uncommon. But even their use is very different from Java's idioms around values that might be null
.
2 Maybe
is a data-type with the definition data Maybe a = Nothing | Just a
, whether the Nothing
constructor contains no other information and the Just
constructor just stores a single value of type a
. So for a given type T
, Maybe T
adds an additional "might not be present" feature and nothing else to the base type T
.
3 And the Haskell version of handling possible absence is usually using combinators like maybe
or fromMaybe
, or pattern matching, all of which have the advantage over if (thing == null)
that the compiler is aware of which part of the code is handling a missing value and which is handling the value.
Upvotes: 8
Reputation: 60503
Short answer: Yes. But also no.
While it's true that an infinite loop, aka undefined
(which are identical in the denotational semantics), inhabits every type, it is usually sufficient to reason about programs as if these values didn't exist, as exhibited in the popular paper Fast and Loose Reasoning is Morally Correct.
Upvotes: 2
Reputation: 153102
Short answer: Yes
As in any sensible Turing-complete language, infinite loops can be given any type:
loop :: a
loop = loop
This (well, this, or maybe this) is occasionally useful as a temporary placeholder for as-yet-unimplemented functionality or as a signal to readers that we are in a dead branch for reasons that are too tedious to explain to the compiler. But it is generally not used at all analogously to the way null
is typically used in Java code.
Normally to signal lack of a value when that's a sensible thing to do, one instead uses
Nothing :: Maybe a
which, while it can't be any type at all, can be the lack of any type at all.
Upvotes: 11
Reputation: 110
Short answer: No
It wouldn't be very type safe to have it. Maybe you can provide more information to your question to understand what you are trying to accomplish.
Edit: Daniel Wagner is right. An infinite loop can be of every type.
Upvotes: 2