2

変数を維持し、他の変数または「セル」が変更されたときにそれらを正しく更新するスプレッドシートのような機能を実装しようとしています。

これまでに見た唯一の実装は、入力されたデータを文字列に格納して評価するものですが、データが変更されてセルを再計算する必要がある場合は、常に文字列を再度評価する必要があります。

私が単純に疑問に思っているのは、Cell1 = "SQUARED (4)" のような文字列を解析して Cell1 = squared 4 にすることができるかどうかです。したがって、値をセルに計算する代わりに、文字列を再度実行する必要があります。再計算が必要な場合は、代わりに実際の関数と値をどこかに保存して、解析と評価を一度だけ行う必要があります。

これが不可能な場合は、コード ジェネレーターを作成する必要があります。これは、非常に高速にする必要があり、大幅なパフォーマンスの低下を許容できないためです。評価、コンパイルなどの速度は問題ではありません。すべてのセルが作成された後、入力データが何百万回も変化し、「スプレッドシート」のようなシステムを介して伝播する速度が重要です。

したがって、これはまずイエスかノーの質問です。可能であれば、例はもちろん役に立ちます。編集:私はこれを自分で理解できないので、それは本当に役立つと思います.

4

2 に答える 2

3

スプレッドシートのようなものを実装することに興味がある場合は、役立つ可能性があることが 2 つあります。

  • まず、Cellz プロジェクトは、F# でのスプレッドシートのサンプル実装です。「=SUM(A1:A10)」のような文字列の単純なパーサーが含まれており、これらの文字列から式ツリーを構築します (これは 1 回だけ行われます)。次に、式の値を計算するエバリュエーターも含まれています。

  • 次に、Luca Bolognese が「Eden」と呼ばれる計算フレームワークの実装についていくつか話しました。このフレームワークでは、セルの観点から計算を記述し、セルの値が変更されると、変更が自動的に反映されます (依存セルのみが再計算されます)。彼はTechMesh London 2012で講演する予定ですが、これはどこかに記録されていると思います (しかし見つかりません)。

Eden の背後にある基本的な考え方は、セルは現在の値と、値が変化したときにトリガーされるイベントを持つものとして表されるということです。

type Cell<'T> =
  abstract Value : 'T  
  abstract Changed : IEvent<unit>

明示的に作成および変更されたセルは変更可能Valueであり、値がユーザーによって変更されたときにイベントをトリガーします。

type MutableCell<'T>(value:'T) = 
  let mutable currentValue = value
  let event = Event<unit>()
  member x.Value 
    with get() = currentValue
    and set(v) = 
        currentValue <- v
        event.Trigger()
  interface Cell<'T> with 
    member x.Value = currentValue
    member x.Changed = event.Publish

次に、何らかの計算の結果として生成されるセルを構築することもできます。これは講演またはブログ投稿のトピックであり、SO の回答ではありませんが、セル内の値を別のセルにマップする単純な変換は次のようになります。

let map f (cell:Cell<_>) =
  let currentValue = ref (f cell.Value)
  cell.Changed.Add(fun () -> currentValue := f cell.Value) 
  { new Cell<_> with
      member x.Value = currentValue.Value
      member x.Changed = cell.Changed }

複数のセルなどの値を組み合わせることができる必要があります。

于 2012-11-02T12:58:21.427 に答える
2

メモ化に関する Don Syme のブログの非常に良い例があります - https://blogs.msdn.com/b/dsyme/archive/2007/05/31/a-sample-of-the-memoization-pattern-in-f .aspx?リダイレクト = true

あなたはこの関数を書きます

let memoize f =
    let cache = Dictionary<_, _>()    
    fun x ->    
        if cache.ContainsKey(x) then cache.[x]    
        else let res = f x    
             cache.[x] <- res    
             res

次に、次のようなメモ化された関数を作成できます。

let memoizedAppend =
    memoize (fun input ->
        printfn "Working out the value for '%A'" input
        String.concat ", " [ for i in 0 .. 9 -> sprintf "%d: %s" i input ])
于 2012-11-02T11:04:21.993 に答える