Еще одно ограничение цитат F#?
Ранее сегодня я столкнулся с ограничением цитат F# и задал вопрос об этом здесь: цитаты F#: переменная может выходить за рамки видимости
Теперь я, возможно, столкнулся с другим ограничением при преобразовании примеров, появляющихся в http://www.cs.rice.edu/~taha/publications/journal/dspg04a.pdf из MetaOcaml в F#.
На этот раз у меня есть этот фрагмент MetaOcaml:
let rec peval2 p env fenv=
match p with
Program ([],e) -> eval2 e env fenv
| Program (Declaration (s1,s2,e1)::tl,e) ->
.<let rec f x = .~(eval2 e1 (ext env s2 .<x>.)
(ext fenv s1 .<f>.))
in .~(peval2 (Program(tl,e)) env (ext fenv s1 .<f>.))>.
и я преобразовал его в
let rec peval2 p env fenv =
match p with
| Program ([], e) -> eval2 e env fenv
| Program (Declaration (s1, s2, e1) :: tl, e) ->
<@ let rec f x = %(eval2 e1 (ext env s2 <@ x @>)
(ext fenv s1 <@ f @>))
in %(peval2 (Program(tl, e)) env (ext fenv s1 <@ f @>)) @>
Я получаю следующую ошибку во время компиляции: This expression was expected to have type int -> Expr<int> but here has type Expr<'a>
с двумя <@ f @>
,
Интуитивно, я думаю, что ошибка имеет большой смысл. Но есть ли способ в F# описать, что я хочу в этом случае?
Пример кода:
open Microsoft.FSharp.Quotations
type Exp =
| Int of int
| Var of string
| App of string * Exp
| Add of Exp * Exp
| Sub of Exp * Exp
| Mul of Exp * Exp
| Div of Exp * Exp
| Ifz of Exp * Exp * Exp
type Def = Declaration of string * string * Exp
type Prog = Program of Def list * Exp
exception Yikes
let env0 = fun x -> raise Yikes
let fenv0 = env0
let ext env x v = fun y -> if x = y then v else env y
let rec eval2 e env fenv =
match e with
| Int i -> <@ i @>
| Var s -> env s
| App (s, e2) -> <@ %(fenv s) %(eval2 e2 env fenv) @>
| Add (e1, e2) -> <@ %(eval2 e1 env fenv) + %(eval2 e2 env fenv) @>
| Sub (e1, e2) -> <@ %(eval2 e1 env fenv) - %(eval2 e2 env fenv) @>
| Mul (e1, e2) -> <@ %(eval2 e1 env fenv) * %(eval2 e2 env fenv) @>
| Div (e1, e2) -> <@ %(eval2 e1 env fenv) / %(eval2 e2 env fenv) @>
| Ifz (e1, e2, e3) -> <@ if %(eval2 e1 env fenv) = 0
then %(eval2 e2 env fenv)
else %(eval2 e3 env fenv) @>
let rec peval2 p env fenv =
match p with
| Program ([], e) -> eval2 e env fenv
| Program (Declaration (s1, s2, e1) :: tl, e) ->
<@ let rec f x = %(eval2 e1 (ext env s2 <@ x @>)
(ext fenv s1 <@ f @>))
in %(peval2 (Program(tl, e)) env (ext fenv s1 <@ f @>)) @>
1 ответ
Я думаю, что вы столкнулись с той же проблемой, что и в предыдущем вопросе - когда я скопировал необходимые декларации из бумаги, я получил:
ошибка FS0446: переменная 'f' связана в кавычке, но используется как часть объединенного выражения. Это недопустимо, поскольку оно может выйти за рамки.
Это имеет смысл - захват переменных, заключенных в кавычки внутри объединенного выражения, не допускается в F#, и это определенно делается в фрагменте кода.
Я не совсем уверен, почему вы получаете другое сообщение об ошибке - если вы можете опубликовать минимальный полный образец, тогда на него можно будет ответить, но вы все равно будете использовать это ограничение захвата переменных. (Что, вероятно, часто используется в MetaOCaml).