One way to define laziness is as follows: a language has strict evaluation if and only if $$f(\bot) = \bot$$ for every function $$f$$ definable in the language.

We can use this definition to solve another problem: comparing algorithms across lazy and strict languages. In particular, it allows us to ask questions like "how many superfluous computations does this traversal perform in a strict language?"

We can form a xiphophyllous tree from an algebraic data type by simply calling its constructors with undefined as an argument, viz.

import Data.List (partition)evens :: [a] -> [a]
evens = fmap snd . fst . partition (even . fst) . zip [0..]list :: [String]
list = ["a", undefined, "b", undefined, "c", undefined, "d", undefined]

You can then verify that evens list evaluates to ["a", "b", "c", "d"], as desired. We say that the application of evens to list is xiphophyllous of degree $$\frac{1}{2}$$; this function will visit half as many leaves in a lazy language as it would in a strict one.

In fact, this generalizes to arbitrary inductively defined data types; when the number of nodes that can be ignored is finite, the minimum of such is well-defined.