📝Clojure Exception: 例外
Clojureにおける例外処理やエラーハンドリングについてまとめ.
refs. 🏷Exceptions 📂Clojure Core Languages
Clojure-Java Exception Interop #
Javaの仕組みを使う.
- Javaのようにtry/catch/finallyが利用できる.
- throwシンタックスで例外を引数にとり連外を発生させる.
- 例外はJavaのクラスで作成できる(Exception. )
- Clojureの記法でex-infoはmessageとmapを受取リ例外を発生させる.
- Clojureの記法でex-dataはex-infoで入力したmapを展開する.
(try
(throw (ex-info "bad" {:a 1 :b 2}))
(catch clojure.lang.ExceptionInfo e
(prn "caught" e)))
連続的なプロシージャ呼び出しのエラーハンドリングどうするか問題 #
Clojureでシステムの外部とやりとりをするときに,ライブラリを使って一連の動作をするシーンがよくある. このとき, 例外処理をどうするか問題. とくにRESP API呼び出しやDBとの通信などで頻発する.
(try
(let [value (func-that-throws)]
(act-on-value value))
(catch Exception e
(log/error e "func-that-throws failed")))
threading-macroをカスタムするようにRailway oriented programming?で記述するほうほうと, try-catchとifを用いてゴリゴリ処理する方法があるようだ.
ref. Clojure とエラーハンドリング at 2021 - Qiita
手続き的な処理をletにずらずら書いていくのはどうも違和感がある(個人的な感想). そうするとスレッディングマクロでbodyに書いていくスタイルはよりClojureらしくてコードの見た目はよい. しかし仕組みがdefaultでClojureに組み込まれていないので汎用的ではない. 手続きが数個に過ぎないならばtryとletとif, そうでなければrailwayを使えばいいかな.
Railway oriented programming(鉄道指向プログラミング) #
鉄道指向プログラミングとは、F# で有名だったプログラミングスタイル. 関数の返り値に正常系の結果 result とそれ以外のパターン err のタプル [result, err] を想定し、実行フローの各プロセスで得られる err が nil でない時 Early-Return をかける方式. (ScalaやHaskellでも合った気がする).
さらに, Javaの関数を呼び出すときにライブラリが例外を挙げずにNullを返すときは some-> というスレッディングマクロを使う方法もClojureのガイドにあった.
ref. some-> - Threading Macros Guide
try-catch and if-let #
tryとletをつかって愚直に書く. コードは汚くなるものの実装も理解もこっちは容易.
try-letというマクロを提供するライブラリもある.
- refs.
🤔そもそもConsistentを考慮してプログラミングするべきなのか #
Clojureは並列プログラミングを強く意識してトランザクションという概念もあるくらいなので一連のオペレーションの途中でエラーが失敗したらその一連の処理自体そのものを失敗させるように作るべきなのかもしれない. つまりConsistent, 一貫性という概念.
slingshot: Enhanced throw and catch for Clojure #
ref. GitHub - scgilardi/slingshot
Clojureは基本的にJavaの例外の仕組みを利用するが, さらにClojureに合わせてカスタマイズしたライブラリ.
たとえば clj-http では HTTP Responseが正常終了以外の場合はこのインスタンスを返すため, slingshotに合わせたエラーハンドリングが期待される.