Colojureの基礎〜状態を扱う〜

Clojureの基礎 〜プロトコル・データ型・レコード〜 - oknknicの日記」に引き続き、基礎メモ。
状態の扱い方についてメモ。

状態を扱うオブジェクト

ref
  • 概要
    • 変更不可なオブジェクトへの、変更可能な参照
    • 参照の変更は、トランザクション内(dosyncマクロ)でのみ可能
  • 生成:ref
    • バリデーション関数は :validator で指定
  • 参照先の取得:
    • deref関数
    • @リーダマクロ
  • 参照の更新(同期):
    • ref-set
    • alter (参照先の読み出しと参照の更新を同時実行)
    • commute (alterの特殊版。具体的には、更新操作の順序が不定である)
  • 参照が他のトランザクションから変更されないように保護:
    • ensure
アトム
  • 概要
    • refの軽量版
    • トランザクションに参加しない。 → 他の値との同期更新が不要な場合に使う
  • 生成:atom
  • 参照の更新(同期)
    • reset!関数
    • swap!
エージェント
  • 概要
  • 参照の更新(非同期):
    • send (ref における commute に似ている。戻り値はエージェントである(非同期なので処理結果はこの時点では判らないため))
    • send-off (必要に応じて別のスレッドプールが割り当てられる版の send。つまり、ブロックしない)
  • 参照の更新エラーのロールバック
    • clear-agent-errors (エージェントの更新で一度でもエラーが発生すると、そのエージェントは読み出し不可になる。この関数で、エラー発生前の状態に戻すことができる)
  • 同期化
    • await (現在のスレッドあるいはエージェントからsendされたアクションがすべて完了するまで、現在のスレッドをブロック)
    • await-for (await のタイムアウト指定版)

束縛(var)

ルート束縛
  • defやdefnの呼び出しで束縛した場合
  • メタデータ「:dynamic」が付与された場合はダイナミックスコープをもつ
  • 任意のスレッドからアクセス可能である
スレッドローカルな束縛
  • bindingマクロで束縛した場合
  • ダイナミックスコープをもつ
  • スレッドローカル(bindingを実行したスレッドにおいて、binding本体の実行を抜けるまでの間、そのスレッド内の任意の場所からのみ参照可能)
  • letの構造に似ているが、letとの違いはダイナミックスコープである点である

(補足)動的束縛によるAOP的な実装

  • bindingによって、その実行内部における任意の束縛を置き換え可能である
  • 例えば以下の用に、呼び出し先の内部で呼び出している関数を書き換えるようなコードを記述できる
(defn ^:dynamic mylogic [] (何らか処理))
(defn ^:dynamic mymain  [] (mylogic))

(defn -main []
  (binding [mylogic #(do (開始ログ出力) (mylogic) (終了ログ出力))]
    (mymain)))

参考

プログラミングClojure 第2版

プログラミングClojure 第2版