要するに、Clojureでは、私が書いたカスタムシーケンスタイプで標準シーケンスAPI(ISeq、IndexedSeqなどのインターフェイスでは定義されていない)から関数を再定義する方法はありますか?
1.巨大なデータファイル
次の形式の大きなファイルがあります。
n
エントリ数を含むlong(8バイト)n
エントリ。各エントリは3つのlong(つまり、24バイト)で構成されます。
2.カスタムシーケンス
これらのエントリにシーケンスが必要です。通常、すべてのデータを一度にメモリに保持することはできず、高速シーケンシャルアクセスが必要なため、次のようなクラスを作成しました。
(deftype DataSeq [id
^long cnt
^long i
cached-seq]
clojure.lang.IndexedSeq
(index [_] i)
(count [_] (- cnt i))
(seq [this] this)
(first [_] (first cached-seq))
(more [this] (if-let [s (next this)] s '()))
(next [_] (if (not= (inc i) cnt)
(if (next cached-seq)
(DataSeq. id cnt (inc i) (next cached-seq))
(DataSeq. id cnt (inc i)
(with-open [f (open-data-file id)]
; open a memory mapped byte array on the file
; seek to the exact position to begin reading
; decide on an optimal amount of data to read
; eagerly read and return that amount of data
))))))
主なアイデアは、リスト内の一連のエントリを先読みして、そのリストから消費することです。キャッシュが完全に消費されるたびに、エントリが残っている場合は、新しいキャッシュリストのファイルから読み取られます。そのような単純な。
このようなシーケンスのインスタンスを作成するには、次のような非常に単純な関数を使用します。
(defn ^DataSeq load-data [id]
(next (DataSeq. id (count-entries id) -1 [])))
; count-entries is a trivial "open file and read a long" memoized
ご覧のとおり、データの形式により、count
非常に簡単かつ効率的に実装できました。
3. drop
O(1)である可能性があります
同じ精神で、再実装したいと思いdrop
ます。これらのデータファイルの形式により、次のdrop
ように、(標準のO(n)ではなく)O(1)で再実装できます。
残りのキャッシュされたアイテムよりも少ない量をドロップする場合は、キャッシュから同じ量をドロップして完了します。
を超える値を削除した場合
cnt
は、空のリストを返します。それ以外の場合は、データファイル内の位置を把握し、その位置にジャンプして、そこからデータを読み取ります。
私の難しさは、、、などdrop
と同じ方法で実装されていないcount
ことです。後者の関数は、同様の名前の静的メソッドを呼び出します。このメソッドは、上記の実装を呼び出しますが、前者は、のインスタンスが呼び出されているシーケンスは、カスタム実装を提供します。first
seq
RT
drop
もちろん、私は何でも名前の付いた関数を提供できますが、drop
それは私が望むことを正確に実行しますが、それは他の人(私の将来の自己を含む)にdrop
毎回ではなくそれを使用することを忘れないようにします。
したがって、問題は次のとおりです。デフォルトの動作をオーバーライドすることは可能drop
ですか?
4.回避策(私は嫌いです)
この質問を書いている間、私は考えられる回避策を見つけました:読書をさらに怠惰にします。カスタムシーケンスは、インデックスを保持し、読み取り操作を延期します。これは、first
が呼び出された場合にのみ発生します。問題は、可変状態が必要にfirst
なることです。最初の呼び出しでデータがキャッシュに読み込まれ、その後のすべての呼び出しでこのキャッシュからデータが返されます。同様のロジックがありますnext
:キャッシュがある場合は、next
それだけです。それ以外の場合は、わざわざデータを入力しないでくださいfirst
。再度呼び出されたときに実行されます。
これにより、不要なディスク読み取りを回避できます。ただし、これはまだ最適ではありません。それでもO(n)であり、簡単にO(1)になる可能性があります。
とにかく、私はこの回避策が好きではありません、そして私の質問はまだ開いています。何かご意見は?
ありがとう。