1.12 Tuples and Options

If you want to combine a small number of values in a single value, and if the values have different types (so that a list doesn’t work), you can use a tuple as an alternative to creating a new datatype with a single variant.

The values form creates a tuple from any number of values. The type of a tuple reveals the type of every component value in the tuple, separating the types with *.

> (values 1 "milk" 'apple)

- (Number * String * Symbol)

(values 1 "milk" 'apple)

> (values '(1 2 3) #f)

- ((Listof Number) * Boolean)

(values '(1 2 3) #f)

Using values, this consume function can effectively return two values each time that it is called:

(define (consume [s : String]) : (Symbol * String)
  (cond
   [(equal? s "milk") (values 'drink "Mmm....")]
   [(equal? s "beets") (values 'eat "Ugh....")]
   [else (values 'sleep "Zzz...")]))

To extract the component values from a tuple, match the tuple with names using define-values.

> (consume "milk")

- (Symbol * String)

(values 'drink "Mmm....")

> (define-values (action response) (consume "beets"))
> action

- Symbol

'eat

> response

- String

"Ugh...."

The convenience functions fst and snd can be used in the special case of a 2-value tuple to extract the first or second component.

> (snd (consume "milk"))

- String

"Mmm...."

Sometimes, instead of always returning multiple values, you’ll want a function that returns either one value or no value. A tuple is no help for that case, but Plait predefines a helpful datatype called Optionof:

(define-type (Optionof 'a)
  (none)
  (some [v : 'a]))

The 'a in this definition of Optionof indicates that you can return any kind of value in a some.

> (define (get-slogan [s : String]) : (Optionof String)
    (cond
     [(equal? s "milk") (some "It does a body good")]
     [else (none)]))
> (get-slogan "milk")

- (Optionof String)

(some "It does a body good")

> (get-slogan "iced tea")

- (Optionof String)

(none)

> (type-case (Optionof String) (get-slogan "moon pie")
    [(some s) s]
    [(none) "no comment"])

- String

"no comment"