Debugging
When debugging, it is often helpful to output the value of an expression or variable.
We might try something like:
def sum(x: Int32, y: Int32): Int32 =
println(x);
println(y);
x + y
Unfortunately this does not work:
❌ -- Type Error -------------------------------------------------- Main.flix
>> Impure function declared as pure.
1 | def sum(x: Int32, y: Int32): Int32 =
^^^
impure function.
The problem is that printing is inherently an effectful operation and hence we
cannot use it to debug our pure functions! We could make our sum
function have
the IO
effect, but that is rarely what we want. Fortunately, Flix has a
built-in debugging facility that allows us to do print-line debugging.
The debug Function
Flix has a debug
function with the same signature as the identity
fuction:
def debug(x: a): a
The debug
"function" isn't really a function; rather its internal compiler
magic that allows you to print any value while fooling the type and effect
system into believing that it is still pure. Using the debug
function this
program:
def sum(x: Int32, y: Int32): Int32 =
debug(x);
debug(y);
x + y
Now compiles and runs.
The debug
function returns its argument. Hence its convenient to use in many
situations.
For example, we can write:
def sum(x: Int32, y: Int32): Int32 = debug(x + y)
to print the value of x + y
and return it.
We can also use it inside e.g. a for-yield
expression:
for(i <- List.range(0, 10);
j <- debug(List.range(i, 10)))
yield (i, j)
Or in a pipeline:
List.range(1, 100) |>
List.map(x -> debug(x + 1)) |>
List.filter(x -> debug(x > 5))
Debug Format
The debug
expression (and its variants) do not use the ToString
type
class. Instead they print the internal Flix representation of the given value.
For example, the expression:
debug(1 :: 2 :: Nil)
prints:
Cons(1, Cons(2, Nil))
We can also print values that do not have a ToString
instance:
debug(x -> x + 123)
prints:
Int32 -> Int32
We can always obtain the ToString
representation by using an interpolated
string. For example:
debug("${x}")
Debug Variants
The debug
function comes in three variants:
debug
: Prints its argument.debug!
: Prints its argument and source location.debug!!
: Prints its argument, source location, and source code.
The following program:
def main(): Unit =
debug("A message");
debug!("Another message");
debug!!("A third message");
()
prints:
"A message"
[C:\tmp\flix\Main.flix:3] "Another message"
[C:\tmp\flix\Main.flix:4] A third message = "A third message"
The third debug!!
variant is intended to be used in situations like:
let x = 123;
let y = 456;
debug!!(x + y)
where it prints:
[C:\tmp\flix\Main.flix:3] x + y = 579
Note: The
debug
expression should not be used in production code.
Warning: The Flix compiler treats the
debug
expression as pure, hence under certain circumstances the compiler may reorder or entirely remove a use ofdebug
.