У меня есть построитель выражений вычислений, который накапливает значение по мере продвижения и имеет множество пользовательских операций. Тем не менее, он не позволяет создавать стандартные конструкторы языка F #, и у меня много проблем с тем, как добавить эту поддержку.
Чтобы дать автономный пример, это мертвое простое и довольно бессмысленное выражение вычисления, которое строит списки F #:
type Items<'a> = Items of 'a list
type ListBuilder() =
member x.Yield(()) = Items []
[<CustomOperation("add")>]
member x.Add(Items current, item:'a) =
Items [ yield! current; yield item ]
[<CustomOperation("addMany")>]
member x.AddMany(Items current, items: seq<'a>) =
Items [ yield! current; yield! items ]
let listBuilder = ListBuilder()
let build (Items items) = items
Я могу использовать это для создания списков просто отлично:
let stuff =
listBuilder {
add 1
add 5
add 7
addMany [ 1..10 ]
add 42
}
|> build
Однако это ошибка компилятора:
listBuilder {
let x = 5 * 39
add x
}
// This expression was expected to have type unit, but
// here has type int.
И вот так:
listBuilder {
for x = 1 to 50 do
add x
}
// This control construct may only be used if the computation expression builder
// defines a For method.
Я прочитал всю документацию и примеры, которые я могу найти, но там что-то я просто не получаю. Каждой подписи .Bind()
или .For()
, которую я пытаюсь, просто приводит к все более запутывающим ошибкам компилятора. Большинство примеров я могу найти либо построить значение по мере продвижения, либо разрешить регулярные конструкторы языка F #, но я не смог найти тот, который делает оба.
Если кто-то может указать мне в правильном направлении, показывая мне, как взять этот пример и добавить поддержку в построителе для привязок let
и for
циклов (минимум - using
, while
и try/catch
было бы здорово, но я, вероятно, смогу понять это, если кто-то меня начнет), тогда я с благодарностью смогу применить урок к моей реальной проблеме.