我如何使用 CustomOperations 实现有状态的构建器,有些让
How can I implement a Stateful Builder with CustomOperations and some let
我正在努力定义一个有状态的构建器,但我无法解决一些编译器错误
type Movement =
| Left of int
| Right of int
type MovementState = Movement list -> Movement list
type MovementBuilder () =
member x.Zero () : MovementState = id
member __.Return x : MovementState = id
member __.Bind(m: MovementState, f: MovementState ) = fun v -> f (m v)
[<CustomOperation("left", MaintainsVariableSpaceUsingBind = true)>]
member x.Left(ms, value) = x.Bind(ms, fun xs -> xs @ [Left value])
[<CustomOperation("right", MaintainsVariableSpaceUsingBind = true)>]
member x.Right(ms, value) = x.Bind(ms, fun xs -> xs @ [Right value])
let movement = MovementBuilder()
[]
|> movement {
left 10
right 20
}
|> printfn "list %A"
//prints [Left 10; Right 20]
但是现在我想引入一个 let!
或 yield
这样我就可以添加额外的项目而无需通过定义的 CustomOperations
例如,我可以这样
[]
|> movement {
left 10
let! _ = (fun xs -> xs @ [Right 99])
//I also tried naming the value
//let! x = (fun xs -> xs @ [Right 99])
//I also tried wrapping it into another function ...
//let! x = fun () -> (fun xs -> xs @ [Right 99])
right 20
}
|> printfn "list %A"
//Should print [Left 10; Right 99; Right 20]
非常感谢任何帮助。
Bonus Karma 将发送用于解释编译器如何将其重写为一系列 Bind
s
感谢
你这里似乎有一个 monadic 类型,它不能 "contain" 任何东西(即 Async<'a> 可以包含 'a 的类型)。
这意味着唯一能够绑定的合理类型是unit
,这使得绑定的签名member __.Bind(m: MovementState, f : unit -> MovementState)
.
这允许您使用 do!
符号来操纵您的移动状态列表,这意味着您需要对左右方法进行一些重写。我相信您也需要在构建器上使用 combine 方法,但是编译器会很快通知您是否这样做! let!
符号在这里没有多大意义,因为您没有要解包的 "contained" 类型。
我在 blog post 中有一个简短的示例,最相关的代码如下:
type PTD = ProvidedTypeDefinition -> ProvidedTypeDefinition
type ProvidedTypeBuilder () =
member __.Zero () : PTD =
id
member __.Return _ : PTD =
id
member __.Bind(m, f : unit -> PTD) =
fun ptd -> (f ()) (m ptd)
member x.Combine(m1 : PTD, m2 : PTD) : PTD =
x.Bind(m1, fun () -> m2)
[<CustomOperation("addMember", MaintainsVariableSpaceUsingBind = true)>]
member x.AddMember(ptd, member') =
let func =
fun (instance : ProvidedTypeDefinition) ->
instance.AddMember member'
instance
x.Bind(ptd, fun () -> func)
作为如何使用 do!
表示法的示例,您可以这样做而不是构建自定义操作:
let ptd = ProvidedTypeBuilder()
let test =
ptd {
addMember (ProvidedProperty("MyProp", typeof<string>))
do! (fun ptd -> ptd.AddObsoleteAttribute("Hey, don't use this anymore"); ptd)
}
我正在努力定义一个有状态的构建器,但我无法解决一些编译器错误
type Movement =
| Left of int
| Right of int
type MovementState = Movement list -> Movement list
type MovementBuilder () =
member x.Zero () : MovementState = id
member __.Return x : MovementState = id
member __.Bind(m: MovementState, f: MovementState ) = fun v -> f (m v)
[<CustomOperation("left", MaintainsVariableSpaceUsingBind = true)>]
member x.Left(ms, value) = x.Bind(ms, fun xs -> xs @ [Left value])
[<CustomOperation("right", MaintainsVariableSpaceUsingBind = true)>]
member x.Right(ms, value) = x.Bind(ms, fun xs -> xs @ [Right value])
let movement = MovementBuilder()
[]
|> movement {
left 10
right 20
}
|> printfn "list %A"
//prints [Left 10; Right 20]
但是现在我想引入一个 let!
或 yield
这样我就可以添加额外的项目而无需通过定义的 CustomOperations
例如,我可以这样
[]
|> movement {
left 10
let! _ = (fun xs -> xs @ [Right 99])
//I also tried naming the value
//let! x = (fun xs -> xs @ [Right 99])
//I also tried wrapping it into another function ...
//let! x = fun () -> (fun xs -> xs @ [Right 99])
right 20
}
|> printfn "list %A"
//Should print [Left 10; Right 99; Right 20]
非常感谢任何帮助。
Bonus Karma 将发送用于解释编译器如何将其重写为一系列 Bind
s
感谢
你这里似乎有一个 monadic 类型,它不能 "contain" 任何东西(即 Async<'a> 可以包含 'a 的类型)。
这意味着唯一能够绑定的合理类型是unit
,这使得绑定的签名member __.Bind(m: MovementState, f : unit -> MovementState)
.
这允许您使用 do!
符号来操纵您的移动状态列表,这意味着您需要对左右方法进行一些重写。我相信您也需要在构建器上使用 combine 方法,但是编译器会很快通知您是否这样做! let!
符号在这里没有多大意义,因为您没有要解包的 "contained" 类型。
我在 blog post 中有一个简短的示例,最相关的代码如下:
type PTD = ProvidedTypeDefinition -> ProvidedTypeDefinition
type ProvidedTypeBuilder () =
member __.Zero () : PTD =
id
member __.Return _ : PTD =
id
member __.Bind(m, f : unit -> PTD) =
fun ptd -> (f ()) (m ptd)
member x.Combine(m1 : PTD, m2 : PTD) : PTD =
x.Bind(m1, fun () -> m2)
[<CustomOperation("addMember", MaintainsVariableSpaceUsingBind = true)>]
member x.AddMember(ptd, member') =
let func =
fun (instance : ProvidedTypeDefinition) ->
instance.AddMember member'
instance
x.Bind(ptd, fun () -> func)
作为如何使用 do!
表示法的示例,您可以这样做而不是构建自定义操作:
let ptd = ProvidedTypeBuilder()
let test =
ptd {
addMember (ProvidedProperty("MyProp", typeof<string>))
do! (fun ptd -> ptd.AddObsoleteAttribute("Hey, don't use this anymore"); ptd)
}