Here's a counter-example: in λ-calculus, every data type boils down to functions. λ-calculus doesn't have nodes or pointers, the only thing it has are functions, therefore everything must be implemented using functions.
This is an example of encoding booleans as functions, written in ECMAScript:
const T = (thn, _ ) => thn,
F = (_ , els) => els,
or = (a , b ) => a(a, b),
and = (a , b ) => a(b, a),
not = a => a(F, T),
xor = (a , b ) => a(not(b), b),
iff = (cnd, thn, els) => cnd(thn, els)();
And this is a cons list:
const cons = (hd, tl) => which => which(hd, tl),
first = list => list(T),
rest = list => list(F);
Natural numbers can be implemented as iterator functions.
A set is the same thing as its characteristic function (i.e. the contains
method).
Note that the above Church Encoding of Booleans is actually how conditionals are implemented in OO languages like Smalltalk, which don't have booleans, conditionals, or loops as language constructs and implement them purely as a library feature. An example in Scala:
sealed abstract trait Boolean {
def apply[T, U <: T, V <: T](thn: => U)(els: => V): T
def ∧(other: => Boolean): Boolean
def ∨(other: => Boolean): Boolean
val ¬ : Boolean
final val unary_! = ¬
final def &(other: => Boolean) = ∧(other)
final def |(other: => Boolean) = ∨(other)
}
case object True extends Boolean {
override def apply[T, U <: T, V <: T](thn: => U)(els: => V): U = thn
override def ∧(other: => Boolean) = other
override def ∨(other: => Boolean): this.type = this
override final val ¬ = False
}
case object False extends Boolean {
override def apply[T, U <: T, V <: T](thn: => U)(els: => V): V = els
override def ∧(other: => Boolean): this.type = this
override def ∨(other: => Boolean) = other
override final val ¬ = True
}
object BooleanExtension {
import scala.language.implicitConversions
implicit def boolean2Boolean(b: => scala.Boolean) = if (b) True else False
}
import BooleanExtension._
(2 < 3) { println("2 is less than 3") } { println("2 is greater than 3") }
// 2 is less than 3