2016-12-12 2 views
2

Могу ли я определить параметр выражения цитаты таким образом, чтобы не только результирующий тип выражения проверял время компиляции , но и выражение сайта вызова.Проверка структуры котировки во время компиляции

позволяет увидеть пример:

type A = { 
    a : int 
} 

type Checker() = 
    static member Check(e : Expr<int>) : ResultType = ... 

Следующим очевидно типа проверки

let a = { a = 1 } 
Checker.Check <@ a.a @> 

В результате в реальном выражении, аналогичном PropertyGet(..., PropertyGet (....), a).

А теперь какой-то другой способ

let getInt (a:A) : int = a.a 

Следующая также компилирует

Checker.Check <@ getInt a @> 

Однако, как можно предотвратить, что второй пример компилируется и разрешить только для PropertyGet с? (как пример).
Я знаю, что могу проверить структуру выражения во время выполнения - но мне нравится иметь проверку времени компиляции.

+5

Вы не можете. Если это критическое требование, я предлагаю использовать библиотеку комбинаторов вместо котировок. –

+0

Как это поможет? – robkuz

+1

Вы можете сделать свои комбинаторы (или, скорее, тип данных, которые они производят) не позволяют создавать недопустимые данные. Вы знаете, «сделать недопустимые данные нерепрезентативными» и все такое. –

ответ

1

Как отметил Федор в комментарии, невозможно обеспечить, чтобы котировки были только определенной формы во время компиляции. Это довольно неудачно, но все эти библиотеки, основанные на котировках (или на основе выражений), страдают от этого (в первую очередь LINQ), и если ваше требование - «только свойство-getters», то я полагаю, вы можете просто оставить это как проверку времени выполнения ,

Если бы я действительно хотел это гарантировать, я бы, вероятно, попытался использовать F# Compiler Service, что позволит вам получить typed expression tree. Затем вы можете пройтись по дереву и найти все цитаты в проекте и сообщить об ошибках (это можно сделать каким-то расширяемым способом как плагин linter, который другие могут извлечь из этого).

Если вы пошли в направлении DSL, то вы могли бы написать, скажем, a |> get "foo" |> get "bar" (с помощью трубы), или a?foo?bar (с помощью оператора ?), но тогда вы потеряете проверки на имена, которые, кажется, хуже, чем не будучи в состоянии проверить правильную форму цитаты.

+0

нетипизированный вариант определенно не подходит ;-) Я, тем не менее, не знаю, как помогут службы компилятора и типизированное дерево выражений. По крайней мере, если мы говорим в контексте нормального рабочего процесса, а не в двухпроходной компиляции. Можете ли вы набросать, как вы это себе представляете? – robkuz

+0

@robkuz Вам обязательно понадобится нечто вроде двухпроходной компиляции. Но вы можете сделать это как интеграцию в FSharpLint (https://github.com/fsprojects/FSharpLint) и использовать его в качестве плагина VS, что сделает процесс приятным. –

Смежные вопросы