F# 使用bind编写跨世界异步函数
我有一条运行良好的铁路管道样本:F# 使用bind编写跨世界异步函数,f#,monad-transformers,f#+,F#,Monad Transformers,F#+,我有一条运行良好的铁路管道样本: 打开FSharpPlus 让福纳= 如果n福纳 >>=funB//它能工作 但是当我想将funB转换为异步函数时,我得到了一个编译错误。从逻辑上讲,这不应该有所不同。相同的输出/输入。。。怎么了 该怎么做才能让它工作 打开FSharpPlus 让福纳= 如果n福纳 >>=funB//编译错误 相同的输出/输入。。。怎么了 不,它们没有相同的输出/输入 如果您查看(>>=)的类型,它类似于'Monad'Monad,因此您的第一个示例可以重写为: let fun
打开FSharpPlus
让福纳=
如果n<10,则正常n
否则错误“不小于10”
让funB n=
如果n<5,则Ok(n,n*2)
否则错误“不小于5”
设funC n=//int->Result
N
|>福纳
>>=funB//它能工作
但是当我想将funB
转换为异步函数时,我得到了一个编译错误。从逻辑上讲,这不应该有所不同。相同的输出/输入。。。怎么了
该怎么做才能让它工作
打开FSharpPlus
让福纳=
如果n<10,则正常n
否则错误“不小于10”
设funB n=async{
如果n<5,则返回Ok(n,n*2)
否则返回错误“不小于5”}
设funC n=//int->Async
N
|>福纳
>>=funB//编译错误
相同的输出/输入。。。怎么了
不,它们没有相同的输出/输入
如果您查看(>>=)
的类型,它类似于'Monad'Monad
,因此您的第一个示例可以重写为:
let funC n = // int -> Result<(int * int), string>
n
|> funA
|> Result.bind funB
因此,我们在这里要做的是将funA
函数“提升”到Async
,然后将其包装在Result
中,它是Result
的单元转换器,因此它有一个绑定操作,在我们的例子中,Async
也负责绑定外部单元
然后我们只需将funB
包装到ResultT
中,并在函数的最后使用Result.run从ResultT
展开
有关F#中分层单子的更多示例
还有其他方法,一些库提供了一些“神奇的工作流”,它使用特殊重载将monad与组合monad(也称为分层monad)结合起来,因此您编写的代码更少,但对类型进行推理并不容易,因为重载不遵循任何替换规则,您必须查看源代码才能理解发生了什么
<>注释:这样的编码是一个很好的练习,但在现实生活中,也要考虑使用异常来避免代码过于复杂。查看运算符的类型<代码> > = 。第二个参数的类型是什么?它与funB的类型匹配吗?谢谢Gustavo的精彩解释。现在一切都有意义了。我认为重要的是funA的输出应该与funB的输入相同,无论funB的输出如何。我误解了原则。再次感谢您的澄清。现在我明白了困惑的来源。是的,在进行正常的函数组合时,这句话是正确的,但在绑定monad时,必须检查monad是否相同。
open FSharpPlus.Data
let funC n = // int -> Result<(int * int), string>
n
|> (funA >> async.Return >> ResultT)
>>= (funB >> ResultT)
|> ResultT.run