我可以为像Builder这样的Builder创建嵌套的Computation Expressions吗?

时间:2015-03-11 20:20:55

标签: f# dsl computation-expression

这就是我想做的事情:

type DirectionBuilder() =
    member self.Yield(()) = []

    [<CustomOperation("left")>]
    member self.Left (acc, degree) = None

    [<CustomOperation("right")>]
    member self.Right (acc, degree) = None 

    [<CustomOperation("velocity")>]
    member self.Velocity (acc, ()) = new VelocityBuilder()


and VelocityBuilder() = 
    member self.Yield(()) = []

    [<CustomOperation("accelerate")>]
    member self.Accesslarate (acc, v) = None

    [<CustomOperation("decelerate")>]
    member self.Decelerate (acc, v) = None


let direction () = new DirectionBuilder()

direction() {
    right 90
    left 30
    velocity() {
        accelerate 1
    }
}

这在

行分解
      velocity() {
  ----^^^^^^^^
  stdin(952,5): error FS3099: 'velocity' is used with an incorrect number of 
  arguments. This is a custom operation in this query or computation 
  expression. Expected 1 argument(s), but given 2.
  > 

有没有向F#解释这个自定义操作确实应该接受计算表达式?

1 个答案:

答案 0 :(得分:0)

我想有一种方法几乎可以获得你想要的语法。您使velocity操作接受VelocityBuilder生成的类型 - 在您的情况下似乎是option。然后创建一个单独的计算并将其传入。

所以你得到这样的东西:

type DirectionBuilder() =
    member self.Yield(()) = []

    [<CustomOperation("left")>]
    member self.Left (acc, degree) = None

    [<CustomOperation("right")>]
    member self.Right (acc, degree) = None 

    [<CustomOperation("velocity")>]
    member self.Velocity (acc, odd: 'a option) = None


type VelocityBuilder() = 
    member self.Yield(()) = []

    [<CustomOperation("accelerate")>]
    member self.Accelerate (acc, v) = None

    [<CustomOperation("decelerate")>]
    member self.Decelerate (acc, v) = None

let dir = new DirectionBuilder()
let vel = new VelocityBuilder()

dir {
    right 90
    left 30
    velocity (vel {
        accelerate 1
    })
}

也就是说,如果你打算编写计算工作流程,你可能应该首先设计一个类型来表示你的计算状态。现在你有语法糖,但没有肉;)

一旦你有了一个类型,如果它变得有用,工作流程可以跟着它。