[英]How to write F# stm as >>= pipeline
有人可以解释一下如何将此FSharpx stm编写为管道吗?
stm {
let! allTops = readTVar tAllTops
let! thisPlayerTops = mapM removeOtherPlayersScores allTops
let! markedTops = mapM markAsNonEmpty thisPlayerTops
return
markedTops
|> Seq.filter fst
|> Seq.map snd
|> List.ofSeq
}
我在想类似haskell的>> =管道。
谢谢!
更新:为了避免混淆,需要进行一些澄清:
我在想,应该能够根据stm.Bind和stm.Return在F#中定义>> =运算符。 我迷路了,试图自己做。
UPDATE2:在Thomas回答之后,我发布了更新版本,我认为它看起来还不错。 如果我理解正确,由于缺少类型类,运算符>> =的功能与Haskell不同。
我同意这对于F#来说不是惯用的,但这可能是一个很好的练习。
readTVar tAllTops
>>= mapM removeOtherPlayersScores
>>= mapM markAsNonEmpty
>>= stm.Return >> Seq.filter fst >> Seq.map snd >> List.ofSeq
|> atomically
谢谢!
Haskell中的>>=
运算符只是绑定操作的符号名,因此您可以在F#中将其定义为stm.Bind
的别名:
let (>>=) v f = stm.Bind(v, f)
使用运算符,您可以按以下方式重写代码:
readTVar tAllTops >>= fun allTops ->
removeOtherPlayersScores allTops >>= fun thisPlayerTops ->
mapM markAsNonEmpty thisPlayerTops >>= fun markedTops ->
markedTops
|> Seq.filter fst
|> Seq.map snd
|> List.ofSeq
|> stm.Return
这当然是一件有趣的事情,也是了解F#中monad的一种好方法(特别是如果您来自Haskell背景),但这不是惯用方式-F#中的惯用方式是显式使用计算。
这种方法的一个局限性(与Haskell相比)是>>=
在单子组上不是多态的,因此您没有获得任何收益。 另外,我认为人们普遍认为使用计算块更具可读性(对于F#开发人员)
在Haskell中使用atomically
将STM表达式转换为IO的主要区别是,将单子结果(也就是计算表达式)绑定到名称(使用<-
运算符)的语法不同,并且默认情况下Haskell列表是惰性的,这意味着您不需要使用Seq
库(据我所知,它在F#中为您提供了惰性列表)。
atomically $ do
allTops <- readTVar tAllTops
thisPlayerTops <- mapM removeOtherPlayersScores allTops
markedTops <- mapM markAsNonEmpty thisPlayerTops
return (map snd . filter fst $ markedTops)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.