title: プログラムのデバッグ支援 author: Yasutaka Higa cover: lang: Japanese # 研究目的 * プログラミングにおいて、ソースコードを改変するとプログラムの挙動も変わる * しかしリファクタリングにおいてはソースコードを変更した後も同じ結果を得たい * ソースコードの改変をモナドとして記述し、実行結果の変化を自動的に検出したい * これによりリファクタリング支援や後方互換性の支援などを行なう # 近況報告 * Deifine Simple Similar * Similar * Similar as Functor * Similar as Applicative Functor * Similar as Monad # Similar * List みたいな感じになりました ``` data Similar a = Single a | Similar a (Similar a) ``` * オリジナルの関数は Single で値を包んでおく必要がある * 全てはモナド、って伏線がここで * 似てる関数は、その値を a に、とオリジナルの関数をsimilarする # Similar Syntax * オリジナルの関数は Single で値を包んでおく必要がある * こうしておかないと、リファクタリング時にオリジナルの関数を修正する必要が出てくる * とは言え関数を呼び出す側は変更しなくてはならないのでリファクタリング時にプログラムが全く変更されない訳では無い * その変わり「関数Aをリファクタリングした関数Bをリファクタリングした関数C」も扱える # Similar Syntax Example ``` double :: Int -> Similar Int double x = Single (2 * x) twicePlus :: Int -> Similar Int twicePlus x = Similar (x + x) (double x) ``` # Similar as Functor * Functor は関数 f を全ての要素に与える * List っぽい ``` instance Functor Similar where fmap f (Single a) = Single (f a) fmap f (Similar a s) = Similar (f a) (fmap f s) ``` # Similar as Monad * mu は Similar (Similar a) -> Similar a * List の List みたいな感じで一旦 flatten する必要が * Similar (Similar a) はこんなの ``` Similar (Single (Similar 1 (Single 1))) (Single (Single (Similar 1 (Single 1)))) ``` # Definition : mu ``` mu :: (Similar (Similar a)) -> Similar a mu (Single s) = s mu (Similar s ss) = similar s (mu ss) ``` * similar は list で言う append みたいな * mu の中で変更を検出しても良いが Eq の instance である必要がある * なので最後の時に値比較をすることに * 値比較 + debugger で追いたい情報を埋めこんでおくと良い? # Definition : Similar as Monad ``` instance Monad Similar where return = Single (Single x) >>= f = f x (Similar x s) >>= f = mu $ Similar (f x) (fmap f s) ``` * Similar (f x) (fmap f s) の type が (Similar (Similar a)) # Get value : Similar ``` same :: (Eq a) => Similar a -> a same (Single x) = x same (Similar x s) = if x == (same s) then x else (error "same") ``` * 今は値が違う、というエラーメッセージのみ # Get value : Similar * こっちは値比較無し * 問答無用で正しく動いている方を取る ``` value :: Similar a -> a value (Single x) = x value (Similar x s) = value s ``` # Execution Samples : bind ``` *Main> return 100 >>= double >>= twicePlus Similar 400 (Single 400) *Main> return 100 >>= double >>= twicePlus >>= plusTwo Similar 402 (Similar 800 (Similar 402 (Single 800))) ``` # Execution Samples : Get value ``` *Main> same $ return 100 >>= double >>= twicePlus >>= plusTwo *** Exception: same *Main> same $ return 100 >>= double >>= twicePlus 400 ``` # Similar as Applicative Functor * ghc 7.8.3 から Monad の instance にするには Applicative にもしておくこと推奨 * Similar 内に function が入ってる場合の挙動 * T f みたいな状態 * こっちも List っぽい感じで全てのパターンを作ってしまう # Define : Similar as Applicative Functor ``` instance Applicative Similar where pure = Single (Single f) <*> s = fmap f s (Similar f s) <*> ss = similar (fmap f ss) (s <*> ss) ``` # summary * List (non-deterministic Monad) っぽい * debugger info の埋め込み * どんな関数がどんな順番で呼ばれたか * Functor raw, Monad raw * 証明しておく必要が * 特に Monoid なのかどうか