hi, I am getting following weird error
The andMode value depends on itself through the following chain of
definitions:
┌─────┐
│ andMode
│ ↓
│ commandsToHandlers
│ ↓
│ commandAnalysis
│ ↓
│ recoverConfigFromInput
└─────┘
────────────────────────────────────────────────────────────────────────────────
it is strange because this loop is exactly what I want to achieve (something perfectly feasible in all languages I know of but Roc)
this error should be about something that's only supported in lazy language like Haskell
for example, of course this can't work:
x = x
because x
can't be defined in terms of itself unless x
is a function and it's referring to itself in the body
similarly, this can't possibly work:
a = b
b = a
or this:
a = b
b = c
c = a
so this compile error is saying the code has something like one of these, where in order to complete a = ...
the compiler has to already know what a
is, which isn't possible
lazy languages like Haskell can do this because they automatically wrap all definitions in function calls, so they end up in the "a function can refer to itself in the body" situation every time even though it doesn't look like it syntactically
ok I get that, it happens most likely because the function, which is calling indirectly itself, enters the game as value(handler) and its called in similar fashion as "C" handlers frequently are. ok I will find workaround somehow
if this was "normal" function I think I can do f -> h -> f ? I think I have done that in the past, am I correct ?
yeah, that should work fine!
btw. is this possible for Roc in the future to recognize that
a = f(.. , c )
b = g(.. , a )
c = h(.. ,b)
a, b and c are in reality functions so it is perfectly ok to have this structure or this will be always limitation ?
so f
is returning a function here?
yes all functions , I don't know if I have described correctly (in terms of math annotation) but I hope you get the point
I have got over my problem this time but at some point handlers may be the easiest way to solve some other problems. I could try something different but still intuitively expectation is that is should work
ah, so if they're all functions, then I think you should be able to make it work by explicitly wrapping them in lambdas, e.g. if the function returned by f
takes 2 argument, then:
a = \arg1, arg2 -> (f ...) arg1 arg2
I think that should work
if I remember right, there was some detail that led us to decide we should require explicit lambdas in that situation, but I don't remember the reasoning anymore
ok, I will check if this tip works for me, thx
ok in my case things aren't as simple as I initially presented
https://github.com/salarii/peek/blob/main/Commands.roc
275 #|> Dict.insert "dsdsa" andMode
Interesting... I can try to look at this today
I won't make it for today, I should be able to take a look on Friday if no one else is available until then.
Today's tasks took longer then expected, I should have time tomorrow
So this is the infinite loop:
addMode
can call recoverConfigFromInput
recoverConfigFromInput
can call commandAnalysis
commandAnalysis
calls commandsToHandlers
commandsToHandlers
calls andMode
This is the simplified version that creates the same error as your code:
app "helloWorld"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" }
imports [pf.Stdout]
provides [main] to pf
main =
Stdout.line "Hello, World!"
andMode : I64 -> List Str
andMode = \num -> recoverConfigFromInput num
recoverConfigFromInput : I64 -> List Str
recoverConfigFromInput = \num -> commandAnalysis num
commandAnalysis : I64 -> List Str
commandAnalysis = \_num ->
Dict.keys (commandsToHandlers)
commandsToHandlers : Dict Str ( I64 -> List Str )
commandsToHandlers =
Dict.empty {}
|> Dict.insert "dsdsa" andMode
Further simplified:
andMode : I64 -> List Str
andMode = \num -> commandAnalysis num
commandAnalysis : I64 -> List Str
commandAnalysis = \_num ->
Dict.keys (commandsToHandlers)
commandsToHandlers : Dict Str ( I64 -> List Str )
commandsToHandlers =
Dict.empty {}
|> Dict.insert "dsdsa" andMode
Even further:
andMode : I64 -> List Str
andMode = \num -> Dict.keys (commandsToHandlers)
commandsToHandlers : Dict Str ( I64 -> List Str )
commandsToHandlers =
Dict.empty {}
|> Dict.insert "dsdsa" andMode
But this code can actually be run:
main = Stdout.line (Inspect.toStr (andMode 0))
andMode : I64 -> List Str
andMode = \num -> Dict.keys (commandsToHandlers)
commandsToHandlers : Dict Str ( I64 -> List Str )
commandsToHandlers =
Dict.empty {}
|> Dict.insert "dsdsa" andMode
That prints ["dsdsa"]
Building does still yield the error:
Screenshot_20240113_171612.png
So the code works because it does not rely on any value of the Dict, only on the keys.
I'm not sure what we should do about this :thinking:
commandsToHandlers
never executes andMode
. What does "depends on" (from the error message) mean in this context? I thought it meant "executes", which would lead to the mentioned infinite loop.
I think depends on means requires a definition of.
Last updated: Jul 06 2025 at 12:14 UTC