如何在F#中正确地丢弃(monadic)计算的结果

Pau*_*tin 1 monads f# haskell computation-expression do-notation

在Haskell中,我可以写:

token: Parser a -> Parser a
token p = do space
             v <- p
             space  
             return v
Run Code Online (Sandbox Code Playgroud)

在F#中,我走到了这一步:

let token = compose {
        let! _ = space
        let! v = parser
        let! _ = space
        return v
    }
Run Code Online (Sandbox Code Playgroud)

换句话说,我必须引入这个未使用的let! _ =绑定来丢弃"空间"解析器(monad)的解析值,这是我不需要的.

如何在F#中避免这些无用的绑定?我尝试过使用do!,但是我收到一个错误(因为我的>>=函数不采用类型单位而是'a):

let (>>=) (p: Parser<'a>) (f: 'a -> Parser<'b>) : Parser<'b> 
Run Code Online (Sandbox Code Playgroud)

这是我的构建器定义:

type ParserComposer() = 
  member x.Bind(p, f) = p >>= f
  member x.Return(y) = ret y
  member x.Zero() = failure
Run Code Online (Sandbox Code Playgroud)

我需要定义>>功能吗?将Combine()添加到构建器?任何想法如何做到这一点?代码示例?

Tom*_*cek 5

假设返回类型为spaceis Parser<unit>(如果它不代表返回某些结果的解析器,则会有意义),您可以编写:

let token = compose {
    do! space
    let! v = parser
    do! space
    return v
}
Run Code Online (Sandbox Code Playgroud)

这只是你所写内容的语法糖 - 因此do! e被翻译为let! _ = e反过来转换为parser.Bind(e, fun _ -> ...).我在Try Joinads上有一个Additive解析器示例,它还定义Combine了一些(可能)有用的东西,但do!关键字只需要Bind.

  • 好的,在这种情况下,space是一个Parser <unit>,所以我可以使用"do!".但是,如果它是其他东西的解析器怎么办?在许多情况下,它确实返回了一些有用的东西,但我只是不需要它.在Haskell中,我只是在这种情况下不绑定它.在F#中处理它的最佳方法是什么?结合我应该使用的东西吗? (2认同)