Do you think making arguments comma delimited on function invocation just like lambda arguments makes this code easier to read / understand?
when Dict.get graph current is
Ok neighbors ->
# filter out all seen neighbors
filtered = List.keepIf neighbors (\n -> !(Set.contains seen n))
# newly explored nodes are added to the FIFO queue
newQueue = List.concat rest filtered
# the new nodes are also added to the seen set
newSeen = List.walk filtered seen Set.insert
bfsHelper isTarget newQueue newSeen graph
Err KeyNotFound ->
bfsHelper isTarget rest seen graph
when Dict.get graph, current is
Ok neighbors ->
# filter out all seen neighbors
filtered = List.keepIf neighbors, \n -> !(Set.contains seen, n)
# newly explored nodes are added to the FIFO queue
newQueue = List.concat rest, filtered
# the new nodes are also added to the seen set
newSeen = List.walk filtered, seen, Set.insert
bfsHelper isTarget, newQueue, newSeen, graph
Err KeyNotFound ->
bfsHelper isTarget, rest, seen, graph
I think commas lead to weird precedence issues. You can't tell if something is a nested function call for a single arg or many args
Str.concat3 "something", Num.toStr data, "more data"
One thing that was proposed before was to allow calling a function with a tuple if wanted instead of the individual args.
I think it got stuck on parsing concerns/vagueness though
An extra note/tip: In current roc, if you have function args that you feel need names or more distinction, you can always use a record:
when Dict.get graph, current is
Ok neighbors ->
# ...
bfsHelper {isTarget, queue: newQueue, seen: newSeen, graph}
Err KeyNotFound ->
bfsHelper {isTarget, rest, seen, graph}
not saying that fits/is needed here, but can help in some of the more complex cases.
Is there a precedence issue with this syntax? <function><space><expr>(,<expr>)*
Using a real example, ROC requires parenthesis around toStr to avoid getting TOO MANY ARGS error
Str.concat (Num.toStr 3) "more data"
Also states, "Are there any missing commas? Or missing parentheses?"
Using commas, I don't think parenthesis would be required here, because there is another space after Num.toStr signifying it's a function call with higher precedence, but ROC would have to know Num.toStr only has one argument
Str.concat Num.toStr 3, "more data"
I guess it is more of a perceived issue than a true issue. As in, to an end user, commas feel like they separate args in a way that parens shouldn't be required. Putting parens in commas feels unnecessary and looks off.
In this case, with commas, you have to write:
Str.concat (Num.toStr 3), "more data"
In general, without some sort of grouping structure, I think commas become hard to parse as a human.
For lambdas and types they have a grouping structure : -> and \ ->. On top of that, they don't allow for arbitrary expressions. You will never see that syntax nested in itself. With function calls, it can nest.
Hmm, I think I actually like Str.concat (Num.toStr 3), "more data" with a comma. Also, the lambda for filtered didn't need the extra parenthesis if a comma is present. Also, I don't think ! would need parenthesis either for Set.contains.
filtered = List.keepIf neighbors (\n -> !(Set.contains seen, n))
vs
filtered = List.keepIf neighbors, \n -> !Set.contains seen, n
we should probably make an FAQ entry for this :big_smile:
it's been discussed before several times, e.g. https://roc.zulipchat.com/#narrow/stream/231634-beginners/topic/syntax.3A.20whitespace.20vs.20comma.20for.20items
Like you said @Brendan Hansknecht , it would probably need tuple grouping syntax just like a record {}, (basically a nameless record?)
Str.concat (Num.toStr 3, "more data")
filtered = List.keepIf (neighbors, \n -> !Set.contains (seen, n))
bfsHelper (isTarget, rest, seen, graph)
This would basically require all arguments to either be a list [], record {}, or tuple ()
Tuples already exist
And we have come full circle :joy:
If a function could only accept at most one argument: primitive value, record, tuple, or list. I'm curious if that would simplify the parser and the evaluation of the AST.
when Dict.get (graph, current) is
Ok neighbors ->
# filter out all seen neighbors
filtered = List.keepIf (neighbors ,\n -> !Set.contains (seen, n))
# newly explored nodes are added to the FIFO queue
newQueue = List.concat (rest, filtered)
# the new nodes are also added to the seen set
newSeen = List.walk (filtered, seen, Set.insert)
bfsHelper (isTarget, newQueue, newSeen, graph)
Err KeyNotFound ->
bfsHelper (isTarget, rest, seen, graph)
I think function currying and lazy evaluation might be used more as well.
I think function currying and lazy evaluation
Roc only has those features if you do them manually
Brian Teague said:
If a function could only accept at most one argument: primitive value, record, tuple, or list. I'm curious if that would simplify the parser and the evaluation of the AST.
we've also talked about this! See #ideas > tuples for function arguments
Last updated: Jun 16 2026 at 16:19 UTC