5

私はこのビットのコードを持っています:

let rec h n z = if n = 0 then z
                else <@ (fun x -> %(h (n - 1) <@ x + %z @>)) n @>

http://www.cs.rice.edu/~taha/publications/journal/dspg04a.pdfの MetaOcaml の例から変換

この論文では、上記の例がパラメーター3および.<1>.(MetaOcaml 表記) を使用して以下を生成することが説明されています。

.<(fun x_1 -> (fun x_2 -> (fun x_3 -> x_3 + (x_2 + (x_1 + 1))) 1) 2) 3>.

ご覧のとおり、 はなどxに置き換えられます。それ以外の場合は、最も内側の のみを参照するためです。x_1x_2xxfun

しかし、F# ではこれは許可されていません。コンパイル時に次のエラーが表示されます。問題は、コンパイルして MetaOcaml の出力と同じセマンティックになるように、これをどのように変更できるかということです。

コメントの更新: PowerPack を使用して実際に見積もりを評価します。しかし、エラーはコンパイル時に発生するため、これとは何の関係もないと思います。これまでのところ QuotationEvaluation は機能しています。ただし、それが最も効率的な実装ではない可能性があることはわかっています。

Tomas の回答への更新:xをグローバルにしたり、スコープをエスケープしたりし たくありません。しかし、私が欲しいのは

let rec h n z = if n = 0 then z
                else (fun x -> (h (n - 1) (x + z))) n

引用符で。あなたの答えは(h 3 <@ 1 @>).Eval() = 4、上記の結果がどこにあるかを示しますh 3 1 = 7。そしてここで、私は答えになりたいです7

4

1 に答える 1

6

F#引用構文は、スコープをエスケープする可能性のある変数をサポートしていないため、Expr操作を使用してツリーを明示的に構築する必要があります。このような何かがトリックを行う必要があります:

open Microsoft.FSharp.Quotations

let rec h n (z:Expr<int>) = 
  if n = 0 then z                
  else 
    let v = new Var("x", typeof<int>)
    let ve = Expr.Var(v)
    Expr.Cast<int>
        (Expr.Application( Expr.Lambda(v, h (n - 1) <@ %%ve + %z @>), 
                           Expr.Value(n)))

ただし、これは非常に人為的な例です(F#では使用できないMetaOCamlでの変数キャプチャを示すため)。のような式を生成するだけ(2 + (1 + ...))です。次のように書くと、同じ結果を得ることができます。

let rec h n (z:Expr<int>) = 
  if n = 0 then z                
  else h (n - 1) <@ n + %z @>

またはさらに良い:

[ 1 .. 4 ] |> List.fold (fun st n -> <@ n + %st @>) <@ 0 @>

また、F#の引用でこの制限に遭遇しました。これがサポートされていれば、それは素晴らしいことです。ただし、F#の引用符は段階的なメタプログラミングには使用されないため、実際にはそれほど大きな問題ではないと思います。これらは、コードを生成するよりも、既存のF#コードを分析する場合に役立ちます。

于 2011-06-20T16:29:49.560 に答える