• 作成:

HaskellでDebug.Traceする時に変数名を2回書かなくても良くなるライブラリdebug-trace-varを公開しました

ncaq/debug-trace-var: You do not have to write variable names twice in Debug.Trace

秒速でコピペしたいHaskellデバッグ用関数 - Qiita を読んで, そう言えばprintデバッグする時に色々と面倒だから開発したかったことを思い出したので, 昼休みに書きました.

printデバッグする時には, どの変数をデバックしているのかわかりやすいように, しばしば以下のように書きます.

import           Debug.Trace

main :: IO ()
main = do
  let a = 1
  traceIO $ "a = " ++ show a

これは変数名を2回書いて面倒くさいし可読性が悪いです.

なのでQuasiQuotesによって2回書かなくても済むようなライブラリを書きました.

{-# LANGUAGE QuasiQuotes #-}
import           Debug.Trace.Var

main :: IO ()
main = do
  let a = 1
  [traceVarIO|a|]

実装

C++なら評価前の変数名取得はプリプロセッサでやるでしょうし, Haskellでもプリプロセッサで実装出来るのかもしれませんが, プリプロセッサのマクロだとimport関係や関数の構造が後でわからなくなるので言語標準の方法で書きました.

これまでTemplate Haskellを使う側ではなくライブラリ作成のために使ったことが無かったので, 一度使ってみたかったという感情もありました.

実装は単純で, 左辺に準クオートされた文字列を置いて, 右辺にlookupValueNameで変数を取得してushowして置いているだけです.

ushowというのはunicode-show :: Stackage Serverの関数で, 日本語などのマルチバイト文字も数値にしないでshowしてくれます.

名前クオートはトップレベルではないと使えないとか, 引数で渡されてきたExpは実行できないとか, 様々な学びがありました.

懸念点

Template Haskellの構文木を直接使っているのでアップデートしたら破壊されそう. Template Haskell初心者なので今ひとつ良い方法が思いつきませんでした.

出来なかったこと

変数だけではなく複雑な式も評価したかったのですが, 方法がわかりませんでした.

Stringとして渡された式を構文木にする方法がわからない.

もっと真面目にやるなら

構造的なログを作って, そこに日時やスタック情報を入れて, 構造的ファイルに出力して, コンソールに出力するものだけa = 1のような形にしたい. そして検索などを簡単に出来るようにしたい. 要はsystemdのjournaldみたいなことをやりたいですね.

HaskellにもRustみたいな宣言的マクロが欲しい…

Cプリプロセッサは単純すぎで管理されてないですし, Template HaskellとQuasiQuotesはこのような単純な用途には構文が面倒すぎます.

HaskellにもRustの宣言的マクロのような, 中ぐらいの強さのコンパイル時処理が欲しいですね.

既存のライブラリ

ndmitchell/debug: Haskell library for debugging

というのがとても便利そうです. まだ使ったことはないですが… Yesod開発でも使えるかどうか今度試したいと思います.