Consider the following 2 definitions of
let external_not x = not x
let match_not = function true -> false | false -> true
Godbolt https://godbolt.org/z/IJJAoU says we get different assembly:
movq %rax, %rbx
movq $4, %rax
subq %rbx, %rax
cmpq $1, %rax
movq $1, %rax
movq $3, %rax
Why is this?
Try this in godbolt
let t _ = true
let f _ = false
And I guess, you will answer you own question. Now, why booleans (and ints) are represented this way, is another question.
Short answer to differentiate them at runtime from pointers.
not function from the standard library is implemented especially by the compiler backend so that more performant assembly is generated. The
match_not function on the other hand is compiled according to the general compilation strategy that applies to any pattern matching (using branches), which results in slightly less efficient assembly.
external not : bool -> bool = "%boolnot"
% in the external declaration indicates a compiler primitive.
https://github.com/ocaml/ocaml/pull/8547 and the other PRs it links seem related