gpt4 book ai didi

f# - 如何编写一个计算表达式构建器来累积一个值并允许标准语言构造?

转载 作者:行者123 更新时间:2023-12-04 00:52:24 24 4
gpt4 key购买 nike

我有一个计算表达式构建器,可以随时建立一个值,并且有许多自定义操作。但是,它不允许标准的 F# 语言结构,而且我在弄清楚如何添加这种支持时遇到了很多麻烦。

举一个独立的例子,这是一个非常简单且毫无意义的计算表达式,用于构建 F# 列表:

type Items<'a> = Items of 'a list

type ListBuilder() =
member x.Yield(()) = Items []

[<CustomOperation("add")>]
member x.Add(Items current, item:'a) =
Items [ yield! current; yield item ]

[<CustomOperation("addMany")>]
member x.AddMany(Items current, items: seq<'a>) =
Items [ yield! current; yield! items ]

let listBuilder = ListBuilder()

let build (Items items) = items

我可以用它来构建列表就好了:
let stuff =
listBuilder {
add 1
add 5
add 7
addMany [ 1..10 ]
add 42
}
|> build

但是,这是一个编译器错误:
listBuilder {
let x = 5 * 39
add x
}

// This expression was expected to have type unit, but
// here has type int.

这是这样的:
listBuilder {
for x = 1 to 50 do
add x
}

// This control construct may only be used if the computation expression builder
// defines a For method.

我已经阅读了我能找到的所有文档和示例,但有些东西我没有得到。每 .Bind().For()我尝试的方法签名只会导致越来越多的令人困惑的编译器错误。我可以找到的大多数示例要么在您进行过程中建立一个值,要么允许使用常规的 F# 语言构造,但我无法找到一个同时具备这两种功能的示例。

如果有人可以通过向我展示如何采用此示例并在构建器中添加对 let 的支持来为我指明正确的方向绑定(bind)和 for循环(至少 - usingwhiletry/catch 会很棒,但如果有人让我开始的话,我可能会弄清楚这些)然后我将能够感激地将类(class)应用于我的实际问题。

最佳答案

最好看的地方是spec .例如,

b {
let x = e
op x
}

被翻译成
   T(let x = e in op x, [], fun v -> v, true)
=> T(op x, {x}, fun v -> let x = e in v, true)
=> [| op x, let x = e in b.Yield(x) |]{x}
=> b.Op(let x = e in in b.Yield(x), x)

所以这显示了哪里出了问题,尽管它没有提供一个明显的解决方案。显然, Yield需要泛化,因为它需要采用任意元组(基于范围内的变量数量)。也许更微妙的是,它还表明 x不在调用 add 的范围内(看到未绑定(bind)的 x 作为 b.Op 的第二个参数?)。要允许您的自定义运算符使用绑定(bind)变量,它们的参数需要具有 [<ProjectionParameter>]属性(并从任意变量中获取函数作为参数),您还需要设置 MaintainsVariableSpacetrue如果您希望以后的运算符(operator)可以使用绑定(bind)变量。这会将最终翻译更改为:
b.Op(let x = e in b.Yield(x), fun x -> x)

以此为基础,似乎没有办法避免在每个操作之间传递一组绑定(bind)值(尽管我很想被证明是错误的)——这将需要你添加一个 Run最后剥离这些值的方法。把它们放在一起,你会得到一个看起来像这样的构建器:
type ListBuilder() =
member x.Yield(vars) = Items [],vars

[<CustomOperation("add",MaintainsVariableSpace=true)>]
member x.Add((Items current,vars), [<ProjectionParameter>]f) =
Items (current @ [f vars]),vars

[<CustomOperation("addMany",MaintainsVariableSpace=true)>]
member x.AddMany((Items current, vars), [<ProjectionParameter>]f) =
Items (current @ f vars),vars

member x.Run(l,_) = l

关于f# - 如何编写一个计算表达式构建器来累积一个值并允许标准语言构造?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23122639/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com