if..then结构中使用零来表示else分支的背后逻辑在计算表达式中。

10

msdn文档中对于计算表达式中Zero方法的解释如下:

在计算表达式中,用于处理if...then语句中空的else分支。

假设我们正在使用一个未定义Zeroidentity计算生成器。

let IdentityBuilder() = 
    member this.Bind(i, f) = f i
    member this.Return(i) = i

let identity = new IdentityBuilder()

以下代码是允许的

identity {
    printf "Hello World"
    return 1
}

然而,下面的代码是不允许的,并会因编译器错误而失败

只有计算表达式构建器定义了“Zero”方法才能使用此控制结构

identity {
    if true then printf "Hello World"
    return 1
}

编译器为什么坚持要在else分支中调用Zero函数?这背后的原理是什么?


顺便说一句,可能与主题无关,但是右侧的 if 与计算表达式的 if 不同,它很可能会按预期工作:ignore <| if true then printf "Hello World" - kkm
有趣,谢谢指出。我确实感觉这可能与我的问题有关。 - Tejas Sharma
我不知道这里是否存在常见的命名规范。我的意思是,在计算表达式的顶层放置 if 和在表达式右侧使用 if 之间的区别。 - kkm
是的,在你编辑了评论并添加了例子后,我删除了那条评论 :) 不过还是谢谢你跟进。 - Tejas Sharma
1个回答

6
是否需要实现 Zero 取决于如何将 if 语句从单子句语法转换为函数调用。如果 if 的两个分支都是计算表达式,那么翻译就不涉及 Zero。如果其中一个分支不是计算表达式或缺失,则翻译会包括 Zero
我将逐一介绍这些情况。 ifelse 都是计算表达式
identity {
    if true then return 1 else return 2
    return 1
}

翻译为:

identity.Combine(
    if true then identity.Return(1) else identity.Return(2), 
    identity.Return(1)
)
分支丢失
identity {
    if true then return 1
    return 1
}

翻译为:

identity.Combine(
    if true then identity.Return(1) else identity.Zero(), 
    identity.Return(1)
)

两个分支被指定,但它们不是句法计算表达式

identity {
    if true then printf "Hello World" else ()
    return 1
}

翻译成:

identity.Combine(
    if true then printf "Hello World" else (); identity.Zero(), 
    identity.Return(1)
)

最后一种情况有点有趣,因为即使if语句返回一个有效的单子值,使用Zero进行翻译仍然会发生。最后一种情况也适用于没有else的if语句,当then部分在语法上不是计算表达式时。编辑:最近我做了更多的研究,发现我的原始答案是错误的。

这样做是不被允许的,对吗? 如果是这样的话:if true then printf "Hello World" else identity.Zero(),那么printf "Hello World"的类型应该是unit,但是identity.Zero()的类型将会是M<'T> - Tejas Sharma
@TejasSharma 这是正确的,一般来说,尽管我认为在你的身份单子中定义 member this.Zero() = () 并使所有内容都能通过类型检查是可以的。但是,这个讨论忽略了类型检查。如果类型不匹配,当编译器无法对 if/then 进行类型推断时,你会收到一个错误提示。 - mrmcgreg
似乎if..then被特殊处理为在表达式的总返回值为unit时调用Zero。我在另一个单子上添加了一些工具,似乎即使在true情况下也会调用Zero。这是否意味着解糖后的版本更像是identity.Combine(identity.Zero(), identity.Delay(() => identity.Return(1)))?这就解释了编译器抱怨的原因。 - Tejas Sharma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接