changeset 50:37a832dff044

Add DeltaM example
author Yasutaka Higa <e115763@ie.u-ryukyu.ac.jp>
date Sun, 15 Feb 2015 17:56:51 +0900
parents ba7f0b5454ab
children 801be6f676bc
files delta.tex delta_with_monad.tex src/deltaM_example.hs src/numberCountM_result.txt
diffstat 4 files changed, 88 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- 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 である。
--- 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 を組み合せることができた。
+
+% }}}
--- 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
--- /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"])))))