F #: Есть ли способ расширить список ключевых слов монады? - PullRequest
29 голосов
/ 14 февраля 2012

Внутри монады F #, если вы говорите let!, компилятор преобразует это в Bind член, который вы определили в конструкторе монад.

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

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

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

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

FooMonadBuilder() {
    bar
}

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

Ответы [ 2 ]

41 голосов
/ 14 февраля 2012

В 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 }
4 голосов
/ 14 февраля 2012

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...