如何将F#stm写为>> =管道

时间:2014-01-13 05:15:47

标签: haskell f# stm

有人可以解释一下如何将这个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

谢谢!

2 个答案:

答案 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)