F# 自定义运算符报告计算表达式中的不正确用法

F# Custom Operator reporting incorrect usage in Computation Expression

我正在创建一个计算表达式 (CE) 来简化建模者的计划定义。我想定义仅在 CE 中可用的功能。在此示例中,编译器表示自定义操作 stepbranch 使用不正确,但我不明白为什么。编译器只是说它们没有正确使用。

Note I know that I could define step and branch outside of the CE to accomplish this. This question is explicitly about using Custom Operators. I want to isolate this logic so that it is only available in the context of the CE.

type Step =
    | Action of string
    | Branch of string list list

type Plan =
    {
        Name : string
        Steps : Step list
    }

type PlanBuilder () =

    member _.Yield _ =
        {
            Name = ""
            Steps = []
        }
    
    member _.Run state = state

    [<CustomOperation "name">]
    member _.Name (state, name) =
        { state with Name = name }

    [<CustomOperation "steps">]
    member _.Steps (state, steps) =
        { state with Steps = steps }

    [<CustomOperation "step">]
    member _.Step (state, step) =
        Action step

    [<CustomOperation "branch">]
    member _.Branch (state, branch) =
        Branch branch

let plan = PlanBuilder ()

let x =
    plan {
        name "Chicken"
        steps [
            // The compiler reports errors for all the 
            // `step` and `branch` calls
            step "1"
            step "2"
            branch [
                [
                    step "3a"
                    step "4a"
                ]
                [
                    step "3b"
                    step "4b"
                ]
            ]
            step "5"
        ]
    }

step 报告的错误

这是因为此时您在列表中。据我所知,CE 关键字仅在 CE 的“顶层”直接起作用。

您可以为单个步骤制作一个“子”CE,并在其中放置关键字,例如

plan {
        name "Chicken"
        steps [
            // The compiler reports errors for all the 
            // `step` and `branch` calls
            step { name "1" }
            step { name "2" }
            branch [
                [
                    step { name "3a" }
                    step { name "4a" }
                ]
            ]
        ]
    }

等等

除了 Isaac Abraham 关于创建子 CE 的建议之外,您还可以考虑废弃 steps 操作并重新定义 step 操作,如下所示:

    [<CustomOperation "step">]
    member _.Step (state, step) =
        { state with 
            Steps = state.Steps @ [ Action step ]
        }

哪个可以让你这样做:

    plan {
        name "Chicken"        
        step "2"
        step "3"
        branch {
            step "3a"
            step "3b"
        }
        step "4"
        step "5"
        branch {
            step "5a"
            step "5b"
        }
    }