"This control construct may only be used if the computation expression builder defines a 'Zero' method" 与 F# 的含义
meaning of "This control construct may only be used if the computation expression builder defines a 'Zero' method" with F#
我有这个代码:
Ok stringBuffer {
let r = get some list....
match r with
| [] -> "no active tasks"
| r -> String.Join("\n", r)
}
stringBuffer 定义为:
[<AutoOpen>]
module StringBuffer =
type StringBuffer = StringBuilder -> unit
type StringBufferBuilder () =
member inline this.Yield (txt: string) = fun (b: StringBuilder) -> Printf.bprintf b "%s" txt
member inline this.Yield (c: char) = fun (b: StringBuilder) -> Printf.bprintf b "%c" c
member inline this.Yield (strings: #seq<string>) = fun (b: StringBuilder) -> for s in strings do Printf.bprintf b "%s\n" s
member inline this.YieldFrom (f: StringBuffer) = f
member this.Combine (f, g) = fun (b: StringBuilder) -> f b; g b
member this.Delay f = fun (b: StringBuilder) -> (f()) b
member this.Zero () = ignore
member this.For (xs: 'a seq, f: 'a -> StringBuffer) =
fun (b: StringBuilder) ->
use e = xs.GetEnumerator ()
while e.MoveNext() do
(f e.Current) b
member this.While (p: unit -> bool, f: StringBuffer) =
fun (b: StringBuilder) -> while p () do f b
member this.Run (f: StringBuffer) =
let b = StringBuilder()
do f b
b.ToString()
let stringBuffer = StringBufferBuilder()
type StringBufferBuilder with
member inline this.Yield (b: byte) = fun (sb: StringBuilder) -> Printf.bprintf sb "%02x " b
我不是 StringBuffer 模块的作者。我经常使用它,因为它使得在 F#
中使用 StringBuilder 超级方便
我可以轻松混合字符串和逻辑:
stringBuffer {
"hello"
if x = 3 then "world"
}
但是,在这个 post 开头的示例中,我收到以下编译错误:
[FS0708] This control construct may only be used if the computation expression builder defines a 'Zero' method.
在计算表达式中,零方法被定义为忽略所以问题可能在那里。但我的问题是:
这个错误是关于什么的?为什么这个特定用例需要实施零方法?
我的理解是,如果表达式 return 什么都没有,则使用零方法,因为它对计算表达式无效;但是既然我指定了一个字符串,为什么这个执行路径return什么都没有?
编辑:
错误截图(Rider/dotnet 5)
现在,错误减少到这种情况:
Ok stringBuffer {
let r = get some list....
match r with
| [] -> "no active tasks"
| r -> String.Join("\n", r)
}
触发错误,但是
let s =
stringBuffer {
let r = get some list....
match r with
| [] -> "no active tasks"
| r -> String.Join("\n", r)
}
Ok s
没有
如果我添加括号,它对我有用:
let result =
Ok (stringBuffer {
let r = [1;2;3]
match r with
| [] -> "no active tasks"
| r -> String.Join("\n", r)
})
printfn "%A" result
没有括号,会出现“零”错误消息,因为函数应用程序是左关联的,因此编译器认为您的意思是这样的:(Ok stringBuffer) { "str" }
。由于 Ok stringBuffer
是缺少 Zero
成员的表达式,因此无法编译。
有趣的是,如果您定义自己的 Ok
运算符 returns 一个有效的构建器,它会编译得很好:
let Ok (sb : StringBufferBuilder) = sb
let result = Ok stringBuffer { "hello "; "world" } // produces: "hello world"
我有这个代码:
Ok stringBuffer {
let r = get some list....
match r with
| [] -> "no active tasks"
| r -> String.Join("\n", r)
}
stringBuffer 定义为:
[<AutoOpen>]
module StringBuffer =
type StringBuffer = StringBuilder -> unit
type StringBufferBuilder () =
member inline this.Yield (txt: string) = fun (b: StringBuilder) -> Printf.bprintf b "%s" txt
member inline this.Yield (c: char) = fun (b: StringBuilder) -> Printf.bprintf b "%c" c
member inline this.Yield (strings: #seq<string>) = fun (b: StringBuilder) -> for s in strings do Printf.bprintf b "%s\n" s
member inline this.YieldFrom (f: StringBuffer) = f
member this.Combine (f, g) = fun (b: StringBuilder) -> f b; g b
member this.Delay f = fun (b: StringBuilder) -> (f()) b
member this.Zero () = ignore
member this.For (xs: 'a seq, f: 'a -> StringBuffer) =
fun (b: StringBuilder) ->
use e = xs.GetEnumerator ()
while e.MoveNext() do
(f e.Current) b
member this.While (p: unit -> bool, f: StringBuffer) =
fun (b: StringBuilder) -> while p () do f b
member this.Run (f: StringBuffer) =
let b = StringBuilder()
do f b
b.ToString()
let stringBuffer = StringBufferBuilder()
type StringBufferBuilder with
member inline this.Yield (b: byte) = fun (sb: StringBuilder) -> Printf.bprintf sb "%02x " b
我不是 StringBuffer 模块的作者。我经常使用它,因为它使得在 F#
中使用 StringBuilder 超级方便我可以轻松混合字符串和逻辑:
stringBuffer {
"hello"
if x = 3 then "world"
}
但是,在这个 post 开头的示例中,我收到以下编译错误:
[FS0708] This control construct may only be used if the computation expression builder defines a 'Zero' method.
在计算表达式中,零方法被定义为忽略所以问题可能在那里。但我的问题是:
这个错误是关于什么的?为什么这个特定用例需要实施零方法?
我的理解是,如果表达式 return 什么都没有,则使用零方法,因为它对计算表达式无效;但是既然我指定了一个字符串,为什么这个执行路径return什么都没有?
编辑:
错误截图(Rider/dotnet 5)
现在,错误减少到这种情况:
Ok stringBuffer {
let r = get some list....
match r with
| [] -> "no active tasks"
| r -> String.Join("\n", r)
}
触发错误,但是
let s =
stringBuffer {
let r = get some list....
match r with
| [] -> "no active tasks"
| r -> String.Join("\n", r)
}
Ok s
没有
如果我添加括号,它对我有用:
let result =
Ok (stringBuffer {
let r = [1;2;3]
match r with
| [] -> "no active tasks"
| r -> String.Join("\n", r)
})
printfn "%A" result
没有括号,会出现“零”错误消息,因为函数应用程序是左关联的,因此编译器认为您的意思是这样的:(Ok stringBuffer) { "str" }
。由于 Ok stringBuffer
是缺少 Zero
成员的表达式,因此无法编译。
有趣的是,如果您定义自己的 Ok
运算符 returns 一个有效的构建器,它会编译得很好:
let Ok (sb : StringBufferBuilder) = sb
let result = Ok stringBuffer { "hello "; "world" } // produces: "hello world"