The Conditional Choice Operator

by Nicolas Wu

Posted on 1 August 2011

Tags: Haskell

A recent reddit post asking for a library of conditional one-liners and combinators reminded me of one of my favourite operators: the conditional choice. Most programmers are used to the so-called McCarthy conditional:

if p then x else y

An alternative way of viewing this is as a ternary operator:

x <| p |> y

This operator is known as the conditional choice, but I’m told that it was introduced by Tony Hoare, so maybe naming it the Hoare conditional would make more sense (it makes an appearance in Hoare’s work on Communicating Sequential Processes and Unifying Theories of Programming, but I haven’t found any references to its original introduction).

Laws

Rendering conditonals as ternary operators makes it clear that there are a number of nice properties that hold true:

Idempotency < x <| p |> x == x

Left-Identity < x <| True |> y == x

Right-Identity < x <| False |> y == y

Left-Distributivity < x <| p |> (y <| q |> z) == (x <| p |> y) <| q |> (x <| p |> z)

Right-Distributivity < (x <| p |> y) <| q |> z == (x <| q |> z) <| p |> (y <| q |> z)

Symmetry < x <| p |> y == y <| not p |> x

Conjunction-Associativity < (x <| p |> y) <| q |> z == x <| p && q |> (y <| q |> z)

Disjunction-Associativity < x <| p |> (y <| q |> z) == (x <| p |> y) <| p || q |> z

Conjunction-Collapse < x <| p |> (y <| p && q |> z) == x <| p |> z

Disjunction-Collapse < (x <| p || q |> y) <| q |> z == x <| q |> z

Abiding (Interchange) < x # y <| p |> v # w == (x <| p |> v) # (y <| p |> w)

These laws are easily proved by considering the cases where p and q are True and False .

Implementation

In Haskell, implementing this operator is quite simple. First we’ll define the right bracket, which takes a predicate and a value x , and returns Nothing if the predicate is True , and returns Just x when it is False :

(|>) :: Bool -> a -> Maybe a True |> _ = Nothing False |> y = Just y

The left bracket is equivalent to fromMaybe , where the resulting value from the application of the right bracket (which evaluates the predicate) is consumed. If the result was Nothing , then we use the value x , otherwise we have Just y , and return y as the result.

(<|) :: a -> Maybe a -> a x <| Nothing = x _ <| Just y = y

Finally we give the operators low infixity precedence, and make them right associative:

infixr 0 <| infixr 0 |>

Defining the operator this way makes the ternary operator right associative, so that:

x <| p |> y <| q |> z == x <| p |> (y <| q |> z) (yz)

Right associativity here is useful so that reading from left to right, the result is the expression to the left of the first predicate that is true.