Operators in JavaScript and Haskell

JavaScript has a handful of builtin infix operators and some convenient tricks you can do with them. Here we look at what you can do with those operators, and how you can do the same things in Haskell.

  1. The basic Boolean operators &&, ||, and ! look much the same between the two languages.
  2. It gets more interesting when we consider what it means in JavaScript to use && and || with things that aren’t Booleans; we’ll see what operators work with the Maybe type to us do similar things in Haskell.
  3. JavaScript has both if-else blocks and the “ternary” ?-: operator; Haskell’s if-then-else plays the role of both of these.

And and Or (Booleans)

We start off very simply: The && and || operators have the same names and the same meanings in JavaScript and Haskell.

JavaScript:

> true && false
false
> true || false
true

Haskell:

λ> True && False
False
λ> True || False
True

The only difference you see here is that True and False are capitalized in Haskell. The capital letters are important: This tells us that True and False are data constructors. A term that starts with a capital letters in Haskell is necessarily a data constructor. (There are other things that start with capital letters, but they are all at the type level.) While JavaScript has true and false as built-in keywords in the language, in Haskell they are data constructors of an ordinary type named Bool.

The definition of the Bool type in the standard library looks like this:

data Bool = True | False

Not (Booleans)

In JavaScript, Boolean “not” is a prefix operator, !.

> !true
false
> !false
true

In Haskell we have a function called not instead of an operator. The effect is much the same, though.

λ> not False
True
λ> not True
False

Just like we saw with && and ||, Haskell’s not is an ordinary function, not a language builtin. Its definition looks something like this:

not :: Bool -> Bool
not True = False
not False = True

Or (Maybe)

Now we move onto stranger things: JavaScript’s || operator isn’t just for Booleans; you can use it with any kind of value.

|| is a builtin operator in JavaScript, but if we were to write it as a function, it would look something like this:

function or(x, y) {
  if (x) {
    return x;
  } else {
    return y;
  }
}

It returns the first argument if present (that is, truthy), and otherwise returns the second argument.

A common idiom is to apply a handful of || operators in sequence to select the first value that is present:

> null || null || 2 || 3 || null
2

This usage of || is quite similar to how we use the <|> operator on Maybe values in Haskell.

λ> Nothing <|> Nothing <|> Just 2 <|> Just 3 <|> Nothing
Just 2

Haskell’s closest equivalent to the concept of “truthiness” and “falsiness” is the Maybe type. Its definition looks like this:

data Maybe a = Nothing | Just a

In JavaScript we mixed nulls and integers together directly, whereas in Haskell we’ve done something more explicit by lifting our integers into the Maybe type to introduce the possibility of the number being absent. In the example above, each Nothing signifies the absence of a number (places where we used null in JavasScript), and Just 2 signifies the number 2.

And (Maybe)

JavaScript has a similar overloading of the && operator. It means something like this:

function and(x, y) {
  if (!x) {
    return x;
  } else {
    return y;
  }
}

The upshot is that for a JavaScript expression of the form a && b && c, if all three values are present (that is, if they are all truthy), then the entire expression evaluates to the last of the values.

> 1 && 2 && 3
3

But if any of the values is missing (represented by a falsy value such as null), then the evaluation terminates and the entire expression evaluates to a falsy value.

> 1 && null && 3
null

This usage of the && operator closely resembles the *> operator on Maybe values in Haskell.

λ> Just 1 *> Just 2 *> Just 3
Just 3
λ> Just 1 *> Nothing *> Just 3
Nothing

You can remember the meaning of *> by thinking of it as an arrow pointing to the right, indicating that it discards the argument on the left and returns the argument on the right. There is a similar function <* that does the opposite: it discards the right argument and returns the left argument.

Ternary conditional

JavaScript has two forms of conditionals. Here we show two ways to write the same code: one using an if-else clause, and one using a ?-: ternary conditional expression.

if (x > 100) {
    console.log('Too high!');
} else {
    console.log('Okay.');
}
console.log(x > 100 ? 'Too high!' : 'Okay.');

Both of these forms of conditional have a Boolean condition, a branch for the true case, and a branch for the false case. The difference is that with if-else, the branches are blocks, and the entire if-else construct is a statement; it doesn’t evaluate to a value, it only produces some effect when it runs. With the ?-: form, the branches are expressions rather than blocks, and the entire ?-: construct is also an expression; it evaluates to a value, which we can then use as the argument to the console.log function. Each form has a benefit and a limitation.

In Haskell, we don’t have to choose. When we translate these two examples into Haskell, both of them are written using an if-then-else expression.

if x > 100
  then putStrLn "Too high!"
  else putStrLn "Okay."
putStrLn (if x > 100 then "Too high!" else "Okay.")

Haskell doesn’t have the same distinction between statements and expressions that JavaScript does. In fact, Haskell doesn’t really have statements at all. Everything is an expression; everything produces some value. We’ll see often that this provides a helpful generality, such as in the above example where we could choose whether to factor out the putStrLn function application without needing to change which syntactic construct we used.

Join Type Classes for courses and projects to get you started and make you an expert in FP with Haskell.