#f#
#f#
Вопрос:
Есть ли способ извлечь параметр из Expr
?
Пример:
let hasStringOption (e:Expr<string option>) =
let myOption : string option = ..some code to get the string option from e
Как бы я получил string option
внутри Expr
и назначил его myOption
?
Комментарии:
1. Это зависит от того, если у вас есть <@ Some (f x) @> , хотели бы вы оценить вызов функции или нет? Если это так, используйте Eval, как упоминал wmeyer; В противном случае, решение Стивена — это правильный путь.
Ответ №1:
В вашем примере string option
представляет возвращаемый тип выражения, поэтому само выражение может быть сколь угодно сложным и требует какой-либо стратегии вычисления, подобной PowerPack, как показал @wmeyer.
Но если у вас действительно есть string option
выражение, вы можете использовать стандартные шаблоны цитирования библиотеки active и отражение для реализации вашей собственной стратегии оценки (общий вариант показан здесь):
module P = Microsoft.FSharp.Quotations.Patterns
let extract (expr:Expr<'a option>) =
match expr with
| P.NewUnionCase (uci, args) ->
if uci.Name = "Some" then
match args.Head with
| P.Value(value, ty) -> Some(value :?> 'a)
else
None:('a option)
let example1 = extract <@ None:int option @>
let example2 = extract <@ Some("hello world") @>
и действительно, такой подход может быть частью вашей собственной стратегии рекурсивного вычисления произвольных выражений с использованием отражения и активных шаблонов, а не медленной и ограниченной промежуточной стратегии LINQ PowerPack.
Комментарии:
1. спасибо за аккуратную функцию 🙂 — Но.. почему вы используете
None:('a option)
? Что это: all about?2.Привет, @ebb, всегда пожалуйста.
:('a option)
ЧастьNone:('a option)
— это просто аннотация типа, которую я изначально использовал, чтобы помочь компилятору определить возвращаемый типextract
. Но это оказывается ненужным, посколькуSome(value :?> 'a)
ветви достаточно для подсказки (сначала я написал ветку None). С другой стороны,:int option
это необходимо для того, чтобы помочь компилятору определить окончательный типexample1
. Но это также можно было бы сделать, поместив аннотацию типа в сам example1:let example1:int option = extract <@ None @>
Ответ №2:
С помощью FSharp.PowerPack.Linq.dll
referenced вы можете сделать:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation
let hasStringOption (e:Expr<string option>) =
let myOption : string option = e.Eval()
myOption.IsSome
printfn "%A" (hasStringOption <@ Some "hello" @>)
printfn "%A" (hasStringOption <@ None @>)
Однако, как сообщается, это довольно медленно и использует выражения LINQ в качестве промежуточного шага.
Ответ №3:
К сожалению (или нет), вы не можете оценить цитаты из F #. F # PowerPack имеет ограниченную возможность компиляции цитат к выражениям LINQ (которые могут быть вычислены).
Комментарии:
1. Я внедрил пользовательский оценщик котировок на основе отражения, который теперь является частью Unquote, code.google.com/p/unquote , начиная с версии 2.0.0. Я измерил, что он работает в 50 раз быстрее, чем вычислитель PowerPack, и он также поддерживает гораздо больше выражений.