2012-02-14 3 views
28

Внутри монады F #, если вы говорите let!, компилятор переводит это в член Bind, который вы определили в построителе монады.F #: Есть ли способ расширить список ключевых слов монады?

Теперь я вижу, есть монады запросов, а shown here on MSDN, где вы можете сказать:

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

и select и count, например, будут переведены на QueryBuilder членов Linq.QueryBuilder.Select и Linq.QueryBuilder.Count.

Вопрос в том, является ли это сопоставление ключевых слов членам, связанным с компилятором F #, или же оно расширяемо? Например, я могу сказать что-то вроде:

FooMonadBuilder() { 
    bar 
} 

и как-то сказать F # компилятор, который bar карты к методу FooMonadBuilder.Bar()?

ответ

39

В F # 2.0 (то есть Visual Studio 2010), нет никакого способа расширить список ключевых слов (другие чем расширение Рамона). Однако механизм запроса в F # 3.0 (Visual Sutdio 11) расширяем, и вы можете определить свои собственные ключевые слова, похожие на select и count.

Вот простой пример, который определяет то, как seq строитель с reverse ключевым словом:

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() 

ПОДРОБНО.Подробнее, как это работает, пока не документированы, но атрибут CustomOperation говорит, что операция должна рассматриваться как особая синтаксис (вы можете установить различные свойства, чтобы указать, как он себя ведет - MaintainsVariableSpace означает, что он не изменяет значения внутри последовательности). Атрибут Projectionparameter указывает, что выражение, следующее за ключевым словом, должно быть неявно преобразовано в функцию.

Теперь mseq строитель поддерживает select и reverse:

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

Не могли бы вы определить соединения с этими расширениями? Я не думаю, что вы можете; просто любопытно. –

+0

Фантастический. С нетерпением ждем прочтения всего этого. Также с нетерпением ждем возможности поиграть с этим атрибутом CustomOperation в монаде, не связанной с запросом, и посмотреть, что произойдет. :) – FSharpN00b

+1

Первое, что я собираюсь сделать с этим, - сделать AI DSL для нового прототипа видеоигр. – gradbot

4

Короткий ответ: нет.

я расширил компилятор, чтобы поддержать это, вы можете прочитать мою статью блога http://ramon.org.il/wp/2011/04/taking-computation-expressions-one-step-further/

+0

Спасибо Рамон. Если он недоступен на этом языке, я сомневаюсь, что в конечном итоге это сделаю, но я с нетерпением жду, чтобы прочитать, как вы это сделали. – FSharpN00b