dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.89k stars 782 forks source link

Copy and update inside a folder function with an anonymous record prints a misleading error message #12489

Open giorgiovilardo opened 2 years ago

giorgiovilardo commented 2 years ago

When using an anonymous record as the initial state of a fold, I noticed that I can't use copy and update expressions in the folder function. See this screenshot:

image

After a bit of troubleshooting on the FSSF Slack server, we noticed that the anonymous record has to be constructed "fully" once, and then the copy and update syntax is available.

image

Code snippet:

type Command =
    | Add of int
    | Sub of int

let anonymousRecordFoldMatchBug x =
    let commandList = [Add 3; Sub 1; Add 10]
    commandList
    |> List.fold (fun state value ->
        match value with
        | Add x -> {| Result = state.Result + x |}
        | Sub x -> {| state with Result = state.Result + x |})
        {| Result=0 |}

Expected behavior

Being able to use the copy and update syntax from the start, or at least a more explicative error message that points out the steps needed to fix the problem.

T-Gro commented 1 year ago

I think the type checker should not look in advance. So in this code construct, it is not yet knowing about the anonymous record supplied as the last argument.

If you rewrote the same thing using ||>like this, it works:

type Command =
    | Add of int
    | Sub of int

let anonymousRecordFoldMatchBug x =
    let commandList = [Add 3; Sub 1; Add 10]
    ({| Result=0 |},commandList)
    ||> List.fold (fun state value ->
        match value with
        | Add x -> {| state with Result = state.Result + x |}
        | Sub x -> {| state with Result = state.Result + x |})
T-Gro commented 1 year ago

What can be improved is the error message in this situation - to refocus it on the fact that "state" is not bound to any particular type (yet), and a type annotation might be needed.

T-Gro commented 1 year ago

The type annotated version would then look like this, alternative to the ||> syntax mentioned above:

image