Mam narzędzie do tworzenia wyrażeń obliczeniowych, które buduje wartość w trakcie pracy i ma wiele niestandardowych operacji. Jednak nie pozwala na standardowe konstrukcje języka F # i mam wiele problemów z ustaleniem, jak dodać tę obsługę.Jak napisać narzędzie do tworzenia wyrażeń obliczeniowych, które gromadzi wartość, a także pozwala na standardowe konstrukcje językowe?
Aby dać przykład autonomiczny, oto wyraz obliczenie martwych proste i dość bezcelowe, która buduje F # list:
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
mogę to wykorzystać do budowania list dobrze:
let stuff =
listBuilder {
add 1
add 5
add 7
addMany [ 1..10 ]
add 42
}
|> build
jednak jest to błąd kompilatora:
listBuilder {
let x = 5 * 39
add x
}
// This expression was expected to have type unit, but
// here has type int.
A więc jest to:
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.
Przeczytałem całą dokumentację i przykłady, które mogę znaleźć, ale jest coś, czego po prostu nie dostaję. Każda próba podpisu metody .Bind()
lub .For()
po prostu prowadzi do coraz bardziej mylących błędów kompilatora. Większość przykładów można znaleźć albo budować wartość, jak idziesz wzdłuż, lub pozwalają na regularne konstrukcje języka F #, ale nie byłem w stanie znaleźć taki, który wykonuje oba.
Jeśli ktoś może wskazać mi w dobrym kierunku, pokazując mi jak zrobić ten przykład i dodać obsługę w konstruktora dla let
wiązań i for
pętli (na minimum - using
, while
i try/catch
byłoby świetnie, ale mogę chyba znajdź je, jeśli ktoś mnie uruchomi), wtedy będę mógł z wdzięcznością zastosować lekcję do mojego rzeczywistego problemu.
Dzięki za wyjaśnienie! Myślę, że główną rzeczą, której mi brakowało, było dostarczenie polecenia "Run", aby usunąć przeniesioną wartość z bieżącej wartości i atrybut "ProjectionParameter". Dokumentacja dotycząca pisania 'For' i innych metod konstruktora będzie miała więcej sensu teraz, gdy kompilator nie oczekuje, że wszystko będzie" jednostką ". –
Wysłałem [tu kontynuuję pytanie] (http://stackoverflow.com/questions/23144744/why-does-this-computation-expression-builder-expect-unit-in-my-for-loop), jeśli masz czas, aby pomóc mi znowu być głupim. –
@kvb, czy usuwasz CE ręcznie lub czy jest jakiś sposób zobaczenia rozszerzenia, nawet jeśli nie sprawdza *? –