我为什么要使用即将来临的let! ...而且!句法?

问题描述

language suggestion指出,优点在链接的文件中有详细说明。我快速浏览了一下,但看不到它的清楚说明。

每个语句都可以并行执行是否有优势,这样我可以提高速度? 还是有某种逻辑可以满足您的需求,而使用通常的单子let!不方便吗?

我了解到,这具有适用性,这意味着它具有以下限制:我无法使用先前的表达式来确定后续表达式的逻辑。那是否意味着要权衡灵活性才能提高效率?

解决方法

一段时间以前,我对Don Syme's description的理解是,let! ... and! ...链中的每一步都会执行,这与您使用let! ... let! ...的情况不同。例如,假设您使用option CE。那你写

option {
    let! a = parseInt("a")
    let! b = parseInt("b")
    return a + b
}

仅执行第一个let!,因为一旦遇到无,CE就会短路。写let! a ... and! b = ...会尝试解析两个字符串。据我了解,虽然不一定是并行的。

当从外部来源解析数据时,我看到了一个巨大的好处。考虑实例运行

parse {
    let! name = tryParse<Name>("John Doe")
    and! email = tryParse<EMail>("johndoe@")
    and! age = tryParse<uint>("abc")
    return (name,email,age)
}

并得到一个Error(["'johndoe@' isn't a valid e-mail"; "'abc' isn't a valid uint"])作为回报,而不只是第一个错误。对我来说很整洁。

,

我为此感到兴奋,有两个原因。潜在的更好的性能,以及某些Monad模式无法适应的特性可以适应Applicative Functor模式。

为了支持已经存在的let!,需要实现BindReturn,即Monad模式。

let!and!需要ApplyPure(不确定确切的F#名称),即应用仿函数模式。

应用函子的功能不如Monads强,但仍然非常有用。例如,在解析器中。

正如菲利普·卡特(Philip Carter)所提到的,可以将Applicative Functor比Monads效率更高,因为它可以缓存它们。

原因是BindM<'T> -> ('T -> M<'U>) -> M<'U>的签名。

实现绑定的一种典型方法是“执行”第一个参数以产生值'T,并将第二个参数传递给它以获取下一步执行的M<'U>

第二个参数是一个可以返回任何M<'U>的函数,这意味着无法进行缓存。

对于Apply,签名为:M<'T -> 'U> -> M<'T> -> M<'U>。由于这两个输入都不是函数,因此您可以将其缓存或进行预计算。

这对于解析器很有用,例如出于性能原因在FParsec中不建议使用Bind

此外; Bind的“缺点”是,如果第一个输入没有产生值'T,则无法获得第二个计算M<'U>。如果您要构建某种类型的验证器monad,则意味着一旦由于输入无效而无法生成有效值,验证就会停止,并且您将无法获得剩余输入的报告。

使用Applicative Functor,您可以执行所有验证器以生成整个文档的验证报告。

所以我认为这很酷!

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...