有人可以解释一下如何将这个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: 托马斯回答后,我发布了更新版本,我觉得它看起来还不错。如果我理解正确,由于缺少类型类,运算符>> =不具有与Haskell相同的功能。
我同意这不是F#的惯用语,但它可能是一个很好的练习。
readTVar tAllTops
>>= mapM removeOtherPlayersScores
>>= mapM markAsNonEmpty
>>= stm.Return >> Seq.filter fst >> Seq.map snd >> List.ofSeq
|> atomically
谢谢!
答案 0 :(得分:1)
Haskell中的>>=
运算符只是 bind 操作的符号名称,因此您可以在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相比)是>>=
不是monad的多态,所以你没有获得任何东西。此外,我认为普遍的共识是使用计算块更具可读性(对于F#开发人员)
答案 1 :(得分:0)
在Haskell中使用atomically
将STM表达式转换为IO的主要区别是将monadic结果(也称计算表达式)绑定到名称(使用<-
运算符)和Haskell的差异语法默认情况下,列表是惰性的,这意味着您不需要使用Seq
库(据我所知,它会为您提供F#中的惰性列表)。
atomically $ do
allTops <- readTVar tAllTops
thisPlayerTops <- mapM removeOtherPlayersScores allTops
markedTops <- mapM markAsNonEmpty thisPlayerTops
return (map snd . filter fst $ markedTops)