compiler
compiler copied to clipboard
Let binding cyclic value detection is stronger than top level
Quick Summary:
Top level definitions allow cyclic values to be declared when the recursive call is guarded behind a lambda.
In let bindings however, they're disallowed more strongly, based on whether the binding itself has arguments. This is a different algorithm, and forbids working programs.
SSCCE
This works (as per the bad-recursion document)
import Json.Decode as Decode exposing (Decoder)
decodeComment : Decoder Comment
decodeComment =
Decode.map4 Comment
(Decode.field "message" Decode.string)
(Decode.field "upvotes" Decode.int)
(Decode.field "downvotes" Decode.int)
(Decode.field "responses" decodeResponses)
decodeResponses : Decoder Responses
decodeResponses =
Decode.map Responses (Decode.list (Decode.lazy (\_ -> decodeComment)))
While this doesn't
import Json.Decode as Decode exposing (Decoder)
decodeResponses : Decoder Responses
decodeResponses =
let
decodeComment =
Decode.map4 Comment
(Decode.field "message" Decode.string)
(Decode.field "upvotes" Decode.int)
(Decode.field "downvotes" Decode.int)
(Decode.field "responses" resulting)
resulting =
Decode.map Responses (Decode.list (Decode.lazy (\_ -> decodeComment)))
in
resulting
Even though these definitions are semantically identical.
- Elm: 0.19.1
Additional Details
Code in question is checkCycles in Canonicalize.Expression.
case binding of
Define def@(Can.Def name args _) ->
if null args then
Result.throw (Error.RecursiveLet name (toNames otherBindings defs))
else
checkCycle otherBindings (def:defs)
This is overly strict and could instead use the toNodeOne and toNodeTwo approach from Canonicalize.Module.
While the above example is indeed liftable to the top level, not all let bindings are, and the alternative (to put everything in the let behind a function call, means potentially a lot of extra computation may occur.
Thanks for reporting this! To set expectations:
- Issues are reviewed in batches, so it can take some time to get a response.
- Ask questions in a community forum. You will get an answer quicker that way!
- If you experience something similar, open a new issue. We like duplicates.
Finally, please be patient with the core team. They are trying their best with limited resources.