I tried moving an old F# (and OCaml before that ) lesson I found on the web to Roc:
let data = [4; 3; 8; 7; 10; 1; 9; 6; 5; 0; 2]
type Tree<'a> =
| Node of Tree<'a> * 'a * Tree<'a>
| Leaf
let rec insert tree element =
match element, tree with
| x, Leaf -> Node (Leaf, x, Leaf)
| x, Node (l, y, r) when x <= y -> Node ((insert l x), y, r)
| x, Node (l, y, r) when x > y -> Node (l, y, (insert r x))
| _ -> Leaf
let tree = List.fold insert Leaf data
let rec find goal queue =
match queue with
| [] -> None
| (Leaf, _)::tail -> find goal tail
| (Node (l, y, r), trace)::tail ->
if y = goal then
Some (List.rev (y::trace))
else
find goal (tail @ [l, y::trace; r, y::trace])
printfn "%A" (find 5 [tree, []])
The above works, but my Roc version gives me an error:
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
}
import pf.Stdout
data = [4, 3, 8, 7, 10, 1, 9, 6, 5, 0, 2]
Tree a : [Node (Tree a, a, Tree a), Leaf]
insert = \tree, element ->
when (element, tree) is
(x, Leaf) -> Node (Leaf, x, Leaf)
(x, Node (l, y, r)) if x <= y -> Node ((insert l x), y, r)
(x, Node (l, y, r)) if x > y -> Node (l, y, (insert r x))
_ -> Leaf
boom = List.walk data Leaf insert
find = \goal, queue ->
when queue is
[] -> None
[(Leaf, _), .. as tail] -> find goal tail
[(Node (l, y, r), trace), .. as tail] ->
if y == goal then
Some (List.reverse (List.prepend trace y))
else
find goal (List.concat tail [(l, List.prepend trace y), (r, List.prepend trace y)])
main =
Stdout.line "$(Inspect.toStr (find 5 [boom, []] ))"
TYPE MISMATCH
This list contains elements with different types:
32│ Stdout.line "$(Inspect.toStr (find 5 [boom, []] ))"
^^
Its 2nd element is a list of type:
List *
However, the 1st element has the type:
[
Leaf,
Node (
a,
Num *,
a,
)c,
] as a
Every element in a list must have the same type!
Any help would be greatly appreciated.
If you move the boom definition inside of main, does it work?
That didn't work for me, ignore it
Thanks for posting the whole function, let me see if I can figure out what the issue is
I find adding type annotations to "pin" the types can help sometimes. Like it enables the compiler to find the issue sooner, or provide a better error message.
Yeah, that's what I'm doing
Could you define an fn and use that instead of []?
empty : Tree a
empty = []
Yeah, with doing that, I found two things:
Leaf is an empty tree, not [], so the list is currently not homogeousfind : Num a, List (Tree (Num a)) -> [Some (Num a), None]
find = \goal, queue ->
when queue is
[] -> None
[(Leaf, _), .. as tail] -> find goal tail
[(Node (l, y, r), trace), .. as tail] ->
if y == goal then
Some (List.reverse (List.prepend trace y))
else
find goal (List.concat tail [(l, List.prepend trace y), (r, List.prepend trace y)])
gives 4 errors, one of which is:
── TYPE MISMATCH in test.roc ───────────────────────────────────────────────────
This 2nd argument to find has an unexpected type:
26│ find goal (List.concat tail [(l, List.prepend trace y), (r, List.prepend trace y)])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This concat call produces:
List (
*,
List (Num a),
)b
But find needs its 2nd argument to be:
List [
Leaf,
Node (
a,
Num a,
a,
)b,
] as a
find : a, List (Tree a) -> [Some a, None] where a implements Eq
is a better type annotation btw
I'm sure I'm missing something, but how is [boom, []] expected to typecheck? Isn't boom a Tree I64 while [] is a List *?
Maybe it should be just [boom] or [boom, Leaf]?
Oh, I think there is a tuple missing cause F# uses , for tuples and ; for lists
Stdout.line "$(Inspect.toStr (find 5 [(boom, [])]))"
That runs for me
Thank you so much! I keep forgetting that it's commas not parentheses that connote tuple in these ML languages!
Francois Green has marked this topic as resolved.
Last updated: Nov 09 2025 at 12:14 UTC