Когда отдавать предпочтение нетипизированным над напечатанными цитатами в F#?
F# имеет как типизированные, так и нетипизированные цитаты кода, и мне интересно, каковы случаи использования, когда один выбирает один над другим?
Является ли различие только удобством, а нетипизированные и типизированные цитаты могут быть преобразованы в каждое во всех случаях или являются типизированными цитатами, например, подмножеством возможных с нетипизированными цитатами?
Есть ли примеры, которые работают только с типизированными, но не с нетипизированными цитатами - или наоборот?
2 ответа
В общем, я бы рекомендовал использовать печатные цитаты, когда вы можете. Как обычно, типы позволят вам статически применять некоторые условия корректности, которые в противном случае могли бы вызвать сбои во время выполнения. Рассматривать:
let one = <@@ "one" @@>
// exception at runtime
let two = <@@ 1 + %%one @@>
в отличие от
let one = <@ "one" @>
// compile time error: the type 'string' does not match the type 'int'
let two = <@ 1 + %one @>
Кроме того, иногда нетипизированные цитаты требуют дополнительных аннотаций типов в тех случаях, когда типизированные цитаты этого не делают:
// ok
let l = <@ [1] @>
let l2 = <@ List.map id %l @>
// fails at runtime (obj list assumed instead of int list)
let l = <@@ [1] @@>
let l2 = <@@ List.map id %%l @@>
// ok
let l = <@@ [1] @@>
let l2 = <@@ List.map (id:int->int) %%l @@>
Однако, если вы строите что-то чрезвычайно общее из цитат, может оказаться невозможным использование типизированных цитат (например, потому что типы не известны статически). В этом смысле нетипизированные цитаты дают вам больше гибкости.
Также обратите внимание, что при необходимости чрезвычайно легко конвертировать между типизированными и нетипизированными цитатами (Expr<_>
в Expr
перейти от типизированного к нетипизированному; использование Expr.Cast
пойти другим путем).
Обычно потребители библиотек обработки цитат будут использовать типизированные цитаты. Принимая во внимание, что авторам обработки цитат необходимо работать с нетипизированными цитатами.
То есть вы не будете часто напрямую создавать нетипизированные цитаты, используя (<@@ @@>)
оператор. Но для рекурсивной обработки цитаты с использованием различных активных шаблонов базовой библиотеки F#, таких как модуль Quotations.Patterns, вы работаете с цитатами в их нетипизированной форме.
Обратите внимание, что Expr<'T>
продолжается Expr
и на самом деле не добавляет много информации к нему. То есть типизированные цитаты на самом деле просто иллюзия, все захваченные метаданные находятся в Expr
объект и доступен только во время выполнения.