# HG changeset patch # User Yasutaka Higa # Date 1423990611 -32400 # Node ID 37a832dff044584203cbd54971a9d8560771b661 # Parent ba7f0b5454ab8056ab0d9ad13bd5df86582e5c56 Add DeltaM example diff -r ba7f0b5454ab -r 37a832dff044 delta.tex --- a/delta.tex Sun Feb 15 14:07:07 2015 +0900 +++ b/delta.tex Sun Feb 15 17:56:51 2015 +0900 @@ -153,8 +153,7 @@ 実際に Haskell で Delta を用いたプログラムの変更例をリスト\ref{src:delta_example}に示す。 \begin{table}[html] - \lstinputlisting[label=src:delta_example, caption=Deltaを用いたプログラムの例] - {src/delta_example.hs} + \lstinputlisting[label=src:delta_example, caption=Deltaを用いたプログラムの例] {src/delta_example.hs} \end{table} リスト\ref{src:delta_example}は1からnの間の整数に含まれる特定の数の個数を調べるプログラム numberCount である。 diff -r ba7f0b5454ab -r 37a832dff044 delta_with_monad.tex --- a/delta_with_monad.tex Sun Feb 15 14:07:07 2015 +0900 +++ b/delta_with_monad.tex Sun Feb 15 17:56:51 2015 +0900 @@ -69,5 +69,75 @@ % }}} +% {{{ DeltaM を用いたプログラムの例 + \section{DeltaM を用いたプログラムの例} \label{section:deltaM_example} +DeltaM を用いてプログラムを記述する。 +今回は簡易的なプログラムのトレースとして、実行時の値を文字列として残すこととする。 +Haskell では処理に対するログなどを残すための Monad として Writer という Monad を提供している。 +リスト\ref{src:delta_example} で示した numberCount プログラムに対し、Writer Monad と Delta Monad を組み合せてトレースの比較を組込む(リスト\ref{src:deltaM_example})。 + + +\begin{table}[html] + \lstinputlisting[label=src:deltaM_example, caption= DeltaM を用いたプログラムの例] {src/deltaM_example.hs} +\end{table} + +Writer と組み合せた Delta を DeltaWithLog 型として定義する。 +型の定義には type 構文を用い、ある型の別名として再定義する。 +まず、 Writer で記録する型を String の List とし、その型を DeltaLog とする。 +DeltaLog を内包する DeltaM として DeltaWithLog 型定義した。 + +また、値をログとするために関数 returnW を定義した。 +これは通常の値から DeltaLog を生成するための関数である。 +tell 関数を用いてログを Writer に書き込み、値を return で保持する。 + +処理を簡易化するために、リストから Delta を作成する関数 deltaFromList を定義しておく。 + +numberCountM プログラムは numberCount プログラムとほとんど違いは無い。 +以下の3つの関数の組み合せで作成されている。 + +\begin{itemize} + \item generatorM + + n を取り、1から nまでのリストを返す + バージョン1とバージョン2に違いは無い。 + + \item numberCountM + + 整数のリストを取り、特定の条件によって絞り込む。 + バージョン1では素数のみを絞り込み、バージョン2では偶数を絞り込む。 + + + \item countM + + リストを取り、その要素の個数を返す。 + バージョン1とバージョン2に違いは無い。 + +\end{itemize} + +唯一の違いは関数が最後に返す Deltaに対して returnW 関数が適用されていることである。 +returnW を用いることで簡易的な値のトレースが得られる。 + + +実行した結果はリスト\ref{src:numberCountM_result}である。 + +\begin{table}[html] + \lstinputlisting[label=src:numberCountM_result, caption= NumberCountM プログラムの実行例] {src/numberCountM_result.txt} +\end{table} + +numberCountM プログラムに対して20を与えて実行した結果である。 +なお、結果は読み易いように整形してある。 +ここで注目して欲しいのが、それぞれがどのような計算結果を辿ったのかを Writer が保持していることである。 + +2つの結果とも、まずは generatorM 関数により1から20までのリストを作る。 +次に numberFilterM 関数によってフィルタされ、それぞれの結果による値が導かれる。 +バージョン1では素数の個数を数えるために8であり、バージョン2では偶数の個数を数えるために10となる。 + +このように、Monad と組み合せることでトレースを得ることができた。 +Writer 以外にも任意の Monad に対して DeltaM が Monad 則を満たす。 +この証明は非常に長いので付録に載せるものとする。% TODO ref + +DeltaM を定義した結果、Delta Monadと Monad を組み合せることができた。 + +% }}} diff -r ba7f0b5454ab -r 37a832dff044 src/deltaM_example.hs --- a/src/deltaM_example.hs Sun Feb 15 14:07:07 2015 +0900 +++ b/src/deltaM_example.hs Sun Feb 15 17:56:51 2015 +0900 @@ -1,46 +1,32 @@ -module Example.DeltaM where - -import Control.Monad.Writer -import Data.Numbers.Primes -- $ cabal install primes - -import Delta -import DeltaM - - --- DeltaM examples - --- DeltaM example utils type DeltaLog = Writer [String] type DeltaWithLog = DeltaM DeltaLog returnW :: (Show a) => a -> DeltaLog a -returnW x = do tell $ [show x] +returnW x = do tell ([show x]) return x -dmap :: (m a -> b) -> DeltaM m a -> Delta b -dmap f (DeltaM d) = fmap f d +deltaAppend :: Delta a -> Delta a -> Delta a +deltaAppend (Mono x) d = Delta x d +deltaAppend (Delta x d) ds = Delta x (deltaAppend d ds) -deltaWithLogFromList :: (Show a) => [a] -> DeltaWithLog a -deltaWithLogFromList xs = DeltaM $ deltaFromList $ fmap returnW xs +deltaFromList :: [a] -> Delta a +deltaFromList = (foldl1 deltaAppend) . (fmap return) --- example : prime filter --- usage : runWriter $ checkOut 0 $ numberCountM 30 -- run specific version --- : dmap runWriter $ numberCountM 30 -- run all version generatorM :: Int -> DeltaWithLog [Int] generatorM x = let intList = [1..x] in - DeltaM $ deltaFromList $ fmap returnW $ replicate 2 intList + DeltaM (deltaFromList (fmap returnW (replicate 2 intList))) numberFilterM :: [Int] -> DeltaWithLog [Int] numberFilterM xs = let primeList = filter isPrime xs evenList = filter even xs in - DeltaM $ deltaFromList $ fmap returnW [primeList, evenList] + DeltaM (deltaFromList (fmap returnW [primeList, evenList])) countM :: [Int] -> DeltaWithLog Int countM xs = let numberCount = length xs in - DeltaM $ deltaFromList $ fmap returnW $ replicate 2 numberCount + DeltaM (deltaFromList (fmap returnW (replicate 2 numberCount))) numberCountM :: Int -> DeltaWithLog Int numberCountM x = generatorM x >>= numberFilterM >>= countM diff -r ba7f0b5454ab -r 37a832dff044 src/numberCountM_result.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/numberCountM_result.txt Sun Feb 15 17:56:51 2015 +0900 @@ -0,0 +1,8 @@ +DeltaM (Delta (WriterT (Identity (8, + ["[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]", + "[2,3,5,7,11,13,17,19]", + "8"]))) + (Mono (WriterT (Identity (10, + ["[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]", + "[2,4,6,8,10,12,14,16,18,20]", + "10"])))))