F#: Есть ли способ расширить список ключевых слов монады?
Внутри монады F#, если вы говорите let!
компилятор переводит это в Bind
член, который вы определили на строителя монад.
Теперь я вижу, что есть монады запросов, как показано здесь на 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()
метод?
2 ответа
В 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 }
Краткий ответ: нет.
Я расширил компилятор для поддержки этого, вы можете прочитать мою статью в блоге http://ramon.org.il/wp/2011/04/taking-computation-expressions-one-step-further/