dudu-av
dudu-av

Reputation: 119

What's the purpose of Just in Elm?

So, I have been doing the Elm track on Exercism.org and I just finished the exercise about the Maybe concept, but one thing is not clear to me yet. What is the purpose of the Just in the definition of Maybe?

type Maybe a = Nothing | Just a

For example, what's the difference between Int and Just Int and why an integer is not considered a Just Int if I don't add the Just word before?

More concretely, when I was trying to solve the RPG problem my first trying resulted in something like this:

type alias Player =
    { name : Maybe String
    , level : Int
    , health : Int
    , mana : Maybe Int
    }

revive : Player -> Maybe Player
revive player =
    case player.health of
        0 ->
            if player.level >= 10 then
                Player player.name player.level 100 100
            else
                Player player.name player.level 100 Nothing
        _ ->
            Nothing

Just to find out that my mistake was in the if statement, that should return Just Person, i.e.:

            if player.level >= 10 then
                Just (Player player.name player.level 100 (Just 100))
            else
                Just (Player player.name player.level 100 Nothing)

Upvotes: 5

Views: 766

Answers (4)

Silvio Mayolo
Silvio Mayolo

Reputation: 70277

If you're coming from a background of dynamic typing like Python then it's easy to see it as pointless. In Python, if you have an argument and you want it to be either an integer or empty, you pass either an integer or None. And everyone just understands that None is the absence of an integer.

Even if you're coming from a poorly-done statically typed language, you may still see it as odd. In Java, every reference datatype is nullable, so String is really "eh, there may or may not be a String here" and MyCustomClass is really "eh, there may or may not really be an instance here". Everything can be null, which results in everyone constantly checking whether things are null at every turn.

There are, broadly speaking, two solutions to this problem: nullable types and optional types. In a language like Kotlin with nullable types, Int is the type of integers. Int can only contain integers. Not null, not a string, not anything else. However, if you want to allow null, you use the type Int?. The type Int? is either an integer or a null value, and you can't do anything integer-like with it (such as add it to another integer) unless you check for null first. This is the most straightforward solution to the null problem, for people coming from a language like Java. In that analogy, Int really is a subtype of Int?, so every integer is an instance of Int?. 3 is an instance of both Int and Int?, and it means both "this is an integer" and also "this is an integer which is optional but exists".

That approach works fine in languages with subtyping. If your language is built up from a typical OOP hierarchy, it's easy to say "well, T is clearly a subtype of T?" and move on. But Elm isn't built that way. There's no subtyping relationships in Elm (there's unification, which is a different thing). Elm is based on Haskell, which is built up from the Hindley-Milner model. In this model, every value has a unique type.

Whereas in Kotlin, 3 is an instance of Int, and also Int?, and also Number, and also Number?, and so on all the way up to Any? (the top type in Kotlin), there is no equivalent in Elm. There is no "top type" that everything inherits from, and there is no subtyping. So it's not meaningful to say that 3 is an instance of multiple types. In Elm, 3 is an instance of Int. End of story. That's it. If a function takes an argument of type Int, it must be an integer. And since 3 can't be an instance of some other type, we need another way to represent "an integer that may or may not be there".

type Maybe a = Nothing | Just a

Enter optional typing. 3 can't be an optional integer, since it's an Int and nothing else. But Just 3, on the other hand... Just 3 is an entirely different value and its type is Maybe Int. A Just 3 is only valid in situations where an optional integer is expected, since it's not an Int. Maybe a is what's called an optional type; it's a completely separate type which represents the type a, but optional. It serves the same purpose and T? in a language like Kotlin, but it's built up from different foundations.

Getting into which one is better would derail this post, and I don't think that's important here. I have my opinions, but others have theirs as well. Optional typing and nullable typing are two different approaches to dealing with values that may or may not exist. Elm (and Haskell-like languages) use one, and other languages might use the other. A well-rounded programmer should become comfortable with both.

Upvotes: 11

TankorSmash
TankorSmash

Reputation: 12747

type Maybe a = Nothing | Just a
---
Just 123 -- is a `Maybe Int`

Means Maybe is a type with an associated generic type a. Similar to C++'s T

template <class T>
class Maybe

using MaybeInt = Maybe<Int>

All Nothing and Just a are are functions (aka constructors) to make a Maybe. In Python it might look like:

def Nothing() -> Maybe:
    return Maybe() # except in elm, it knows the returned Maybe came from a
                   # Nothing, so there's some machinery missing here

def Just(some_val) -> Maybe:
    return Maybe(some_val)

So if a function returns a Maybe, the returned value has to be passed through one of the two Nothing or Just constructors.

Upvotes: 0

Arnon Rotem-Gal-Oz
Arnon Rotem-Gal-Oz

Reputation: 25909

Just in Elm is a tag but in this context you can think of it like a function that takes a value of type Int, and return something of the type Maybe Int.

Upvotes: 0

Bergi
Bergi

Reputation: 664538

Why an integer is not considered a Just Int if I don't add the Just word before?

Simply because without the constructor (Just), it's only an integer and not something else. There's no automatic type conversion, you have to be explicit about what you want. Would you also consider allow writing 100 if you meant the single-element list [100]? Soon, you would have no idea what it meant if someone wrote 100.

This is not specific to Maybe and its Just variant, this is the rule for all data types. There is no exception for Maybes, even if the language is confusing - an Int is just an Int, but not a Just Int.

Upvotes: 3

Related Questions