Example: Custom Show type class
This mirrors rex/examples/typeclasses_custom_show.rex.
Goal
Define your own show-printing API that turns values into string without baking formatting into
every call site.
We’ll build it up in layers:
- define the class
- add a base instance (
i32) - add a structured type (
Point) - (optional) add a container instance (
List a)
class DemoShow a
demo_show : a -> string
type Point = Point { x: i32, y: i32 }
instance DemoShow i32
demo_show = \_ -> "<i32>"
instance DemoShow Point
demo_show = \p -> "Point(" + demo_show p.x + ", " + demo_show p.y + ")"
demo_show (Point { x = 1, y = 2 })
Extending it
Add an instance DemoShow (List a) <= DemoShow a (see rex/examples/typeclasses_custom_show.rex)
and call demo_show [Point { x = 1, y = 2 }].
A worked DemoShow (List a) instance
Here is the list instance from the repo example, with commentary:
class DemoShow a
demo_show : a -> string
instance DemoShow i32
demo_show = \_ -> "<i32>"
instance DemoShow (List a) <= DemoShow a
demo_show = \xs ->
let
step = \out x ->
if out == "["
then out + demo_show x
else out + ", " + demo_show x,
out = foldl step "[" xs
in
out + "]"
Why the <= DemoShow a constraint?
Because the implementation calls demo_show x for list elements, so it requires DemoShow a.
Worked examples
Example: use "; " as the list separator
Problem: format list output with semicolons.
class DemoShow a
demo_show : a -> string
instance DemoShow i32
demo_show = \_ -> "<i32>"
instance DemoShow (List a) <= DemoShow a
demo_show = \xs ->
let
step = \out x ->
if out == "["
then out + demo_show x
else out + "; " + demo_show x,
out = foldl step "[" xs
in
out + "]"
demo_show [1, 2, 3]
Why this works: only the separator string changed; the fold structure stays the same.
Example: DemoShow bool
Problem: add show-print support for booleans.
class DemoShow a
demo_show : a -> string
instance DemoShow bool
demo_show = \b -> if b then "true!" else "false!"
(demo_show true, demo_show false)
Why this works: the instance defines one method body specialized to bool.
Example: DemoShow (Option a)
Problem: print Some(...) and None for options.
class DemoShow a
demo_show : a -> string
instance DemoShow i32
demo_show = \_ -> "<i32>"
instance DemoShow (Option a) <= DemoShow a
demo_show = \ox ->
match ox
when Some x -> "Some(" + demo_show x + ")"
when None -> "None"
(demo_show (Some 1), demo_show None)
Why this works: pattern matching distinguishes constructors and delegates formatting of payloads.