F#: Is there a way to extend the monad keyword list?

北城余情 提交于 2019-12-31 08:11:40

问题


Inside an F# monad, if you say let!, the compiler translates that to a Bind member that you've defined on the monad builder.

Now I see there are Query monads, as shown here on MSDN, where you can say:

query {
    for student in db.Student do
    select student
    count
}

and the select and count, for example, will be translated to the QueryBuilder members Linq.QueryBuilder.Select and Linq.QueryBuilder.Count.

My question is, is this mapping of keywords to members hardwired into the F# compiler, or is it extensible? For example, can I say something like:

FooMonadBuilder() {
    bar
}

and somehow tell the F# compiler that bar maps to a FooMonadBuilder.Bar() method?


回答1:


In F# 2.0 (that is Visual Studio 2010), there is no way to extend the keyword list (other than Ramon's extension). However, the query mechanism in F# 3.0 (Visual Sutdio 11) is extensible and you can define your own keywords similar to select and count.

Here is a basic example that defines something like seq builder with reverse keyword:

type SeqBuilder() =
    // Standard definition for 'for' and 'yield' in sequences
    member x.For (source : seq<'T>, body : 'T -> seq<'R>) =
      seq { for v in source do yield! body v }
    member x.Yield item =
      seq { yield item }

    // Define an operation 'select' that performs projection
    [<CustomOperation("select")>]
    member x.Select (source : seq<'T>, [<ProjectionParameter>] f: 'T -> 'R) : seq<'R> =
        Seq.map f source

    // Defines an operation 'reverse' that reverses the sequence    
    [<CustomOperation("reverse", MaintainsVariableSpace = true)>]
    member x.Expand (source : seq<'T>) =
        List.ofSeq source |> List.rev

let mseq = SeqBuilder()

The details how this works are not yet documented, but the CustomOperation attribute says that the operation should be treated as a special syntax (you can set various properties to specify how it behaves - MaintainsVariableSpace means that it does not change the values inside sequence). The Projectionparameter attribute specifies that the expression following the keyword should be implicitly converted to a function.

Now, the mseq builder supports both select and reverse:

let q = mseq { for i in 1 .. 10 do
               select (i + 100)
               reverse }



回答2:


Short answer: no.

I've extended the compiler to support that, you're welcome to read my blog article http://ramon.org.il/wp/2011/04/taking-computation-expressions-one-step-further/



来源:https://stackoverflow.com/questions/9272285/f-is-there-a-way-to-extend-the-monad-keyword-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!