Haskell 如何将F#stm编写为>>;=管道
有人能解释一下如何将这个FSharpx stm作为管道编写吗Haskell 如何将F#stm编写为>>;=管道,haskell,f#,stm,Haskell,F#,Stm,有人能解释一下如何将这个FSharpx stm作为管道编写吗 stm { let! allTops = readTVar tAllTops let! thisPlayerTops = mapM removeOtherPlayersScores allTops let! markedTops = mapM markAsNonEmpty thisPlayerTops return markedTops
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#中的>>=运算符。我试着自己去做,但是我迷路了
更新2:
在托马斯的回答之后,我发布了更新版本,我认为它看起来还不错。如果我理解正确的话,由于缺少类型类,操作符>>=没有Haskell中的功能
我同意这不是F#的惯用法,但它可能是一个很好的练习
readTVar tAllTops
>>= mapM removeOtherPlayersScores
>>= mapM markAsNonEmpty
>>= stm.Return >> Seq.filter fst >> Seq.map snd >> List.ofSeq
|> atomically
谢谢 STM表达式转换为IO的主要区别是使用Haskell中的
原子方式
,即将一元结果(又称计算表达式)绑定到名称的差异语法(使用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#中单子的一个好方法(特别是如果你来自Haskell的背景),但它不是一种惯用的风格——F#中惯用的风格是显式地使用计算
这种方法的一个局限性(与Haskell相比)是>=
在单子上不是多态的,所以你什么也得不到。另外,我认为大家普遍认为使用计算块更具可读性(对于F#开发者)我知道这是等效的haskell代码,但我想要的是等效于我原来的stm的F#代码。我在想,应该可以用stm.Bind和stm.Return来定义F#中的>>=运算符。我自己也试着这么做,但我迷路了。哦,对不起,我完全误解了这个问题!我不确定是怎么回事我应该读stm.Bind类型。我根据您的运算符添加了一个更新的解决方案>>=谢谢!
readTVar tAllTops >>= fun allTops ->
removeOtherPlayersScores allTops >>= fun thisPlayerTops ->
mapM markAsNonEmpty thisPlayerTops >>= fun markedTops ->
markedTops
|> Seq.filter fst
|> Seq.map snd
|> List.ofSeq
|> stm.Return