私は非常に頻繁に再作成される依存グラフ(ASTのようなもの)を構築するTheGamma(GitHub)で同様のことが最近必要でした(エディタでコードを変更して再解析されます)。ライブプレビューでは計算に時間がかかることがあるので、できるだけ前のグラフを再利用したいと思っていました。
私がやっていることは、各ノードに「シンボル」を付けることです。キーは、いくつかのノードの種類のコードAdd
について(0、1である -
type Expr =
| Add of ExprNode * ExprNode
| Lit of int
and ExprNode(expr:Expr, symbol:int) =
member x.Expression = expr
member x.Symbol = symbol
override x.GetHashCode() = symbol
override x.Equals(y) =
match y with
| :? ExprNode as y -> y.Symbol = x.Symbol
| _ -> false
私は、ノードのキャッシュを保持し実行します。同じシンボルを持つ2つのノードが、私はあなたが効率的な等価性のテストに使用できると思いますこれは、同じですLit
など)、およびすべてのネストされたノードのシンボルリテラルでは、数値自体も追加します。つまり、同じリテラルを2回作成すると同じノードが得られます。だから、ノードを作成することは次のようになります。
let node expr ctx =
// Get the key from the kind of the expression
// and symbols of all nested node in this expression
let key =
match expr with
| Lit n -> [0; n]
| Add(e1, e2) -> [1; e1.Symbol; e2.Symbol]
// Return either a node from cache or create a new one
match ListDictionary.tryFind key ctx with
| Some res -> res
| None ->
let res = ExprNode(expr, nextId())
ListDictionary.set key res ctx
res
ListDictionary
モジュールは、キーが整数のリストであるとnextId
は次のIDを生成するための通常の機能である可変辞書です:だから、
type ListDictionaryNode<'K, 'T> =
{ mutable Result : 'T option
Nested : Dictionary<'K, ListDictionaryNode<'K, 'T>> }
type ListDictionary<'K, 'V> = Dictionary<'K, ListDictionaryNode<'K, 'V>>
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module ListDictionary =
let tryFind ks dict =
let rec loop ks node =
match ks, node with
| [], { Result = Some r } -> Some r
| k::ks, { Nested = d } when d.ContainsKey k -> loop ks (d.[k])
| _ -> None
loop ks { Nested = dict; Result = None }
let set ks v dict =
let rec loop ks (dict:ListDictionary<_, _>) =
match ks with
| [] -> failwith "Empty key not supported"
| k::ks ->
if not (dict.ContainsKey k) then
dict.[k] <- { Nested = Dictionary<_, _>(); Result = None }
if List.isEmpty ks then dict.[k].Result <- Some v
else loop ks (dict.[k].Nested)
loop ks dict
let nextId =
let mutable id = 0
fun() -> id <- id + 1; id
私はあなた自身のキャッシュメカニズムを実装する必要があると言っていると思いますが、これは私のためにはうまくいきましたし、あなたのケースでこれを行う方法をヒントするかもしれません!
「平等」を比較する理由は何ですか? F#組み込みの 'equal'は遅いですが、木の比較を行うことは関係なく高価になります。 オブジェクトの同一性と値の平等性を比較する必要がある場合は、「CustomEquality」属性を使用できます。 – FuleSnabel
[このスレッド](https:// www。dragonnixx)の[my reply](https://www.reddit.com/r/Compilers/comments/6rrn36/how_to_speed_up_equality_checking/dl8yvgl/?st=j6129dpv&sh=4d371f23)を参照してください。 reddit。com/r /コンパイラ/コメント/ 6rrn36/how_to_speed_up_equality_checking /)私がやっていることは、多変量の特殊化と呼ばれ、私の言語での再帰を処理するために必要です。私は今、それをどうやってやるのか考えていると思う。 –
この質問はちょっと考えられます。具体的に何を求めているのですか? –