11.アロー記法
wireは、入力aを受けて、出力bを出すことで、その振る舞いを表しているが、前の記事では、入力aの存在が分かりにくかったので、wireの本質をとらえにくかったかもしれない。
そこで、ここでは、前の記事で用いたプログラムを等価なアロー記法で表すことにする。
アロー記法の基本的な表現は、b <- wire -< aである。ここで、aがwireへの入力、bがwireからの出力である。
なお、以下のプルグラムでは、アロー記法とNetwireを用いるために、プログラムの最初に次のインポート文などを書いておく。
{-# LANGUAGE Arrows #-} import Prelude hiding ((.)) -- To use (.) in the scope of Categories instead import Control.Wire import FRP.Netwire
11.1 簡単な振舞い
定数23は出力するWire型の値は次のようになる。
ex1 :: Monad m => Wire s () m a Int ex1 = pure 23 main1 :: IO () main1 = testWire (pure ()) ex1
これを、アロー記法で記述すると以下のようになる。
ex1 :: Monad m => Wire s () m a Int ex1 = proc _ -> do b <- pure 23 -< () returnA -< b main1 :: IO () main1 = testWire clockSession_ ex1
23にかわって、Double型の値を外部から与え、これを出力するWire型の値を作成する。
ex2 :: Monad m => Double -> Wire s () m a Double ex2 x = pure x main2 :: Double -> IO () main2 x = testWire (pure ()) $ ex2 x
これを、アロー記法で記述すると以下のようになる。
ex2 :: Monad m => Double -> Wire s () m a Double ex2 x = proc x -> do b <- pure x -< () returnA -< b main2 :: Double -> IO () main2 x = testWire clockSession_ $ ex2 x
次の例は、外部から値を得て、それを利用した計算結果を出力するWire型の値である。
ex3 :: Monad m => Double -> Wire s () m a Double ex3 x = pure $ x * x - 2 main3 :: Double -> IO () main3 x = testWire (pure ()) $ ex3 x
これを、アロー記法で記述すると以下のようになる。
ex3 :: Monad m => Double -> Wire s () m a Double ex3 x = proc x -> do b <- pure $ x * x - 2 -< () returnA -< b main3 :: Double -> IO () main3 x = testWire clockSession_ $ ex3 x
次は、外部から文字列を与え、それを出力するWire型の値である。
ex4 :: Monad m => String -> Wire s () m a String ex4 x = pure x main4 :: String -> IO () main4 x = testWire (pure ()) $ ex4 x
これを、アロー記法で記述すると以下のようになる。
ex4 :: Monad m => String -> Wire s () m a String ex4 x = proc x -> do b <- pure x -< () returnA -< b main4 :: String -> IO () main4 x = testWire clockSession_ $ ex4 x
11.2 時間
Wire型の値は、時計を有することが可能であるが、それ自身の時計の現在の時刻を出力するWire型の値は次のようになる。
ex5 :: (Monad m, HasTime t s) => Wire s () m a t ex5 = time main5 :: IO () main5 = testWire clockSession_ ex5
これを、アロー記法で記述すると以下のようになる。
ex5 :: (Monad m, HasTime t s) => Wire s () m a t ex5 = proc _ -> do b <- time -< () returnA -< b main5 :: IO () main5 = testWire clockSession_ ex5
Wire型の値が4倍の速さで120からカウントダウンを行うときは、次のようになる。
ex6 :: (Monad m, HasTime t s) => Wire s () m a t ex6 = liftA2 (\speed countdown -> countdown - 4*speed) time (pure 120) main6 :: IO () main6 = testWire clockSession_ ex6
これを、アロー記法で記述すると以下のようになる。
ex6 :: (Monad m, HasTime t s) => Wire s () m a t ex6 = proc _ -> do b <- liftA2 (\speed countdown -> countdown - 4*speed) time (pure 120) -< () returnA -< b main6 :: IO () main6 = testWire clockSession_ ex6
11.3 位置、速度、加速度
等速運動を行うWire型の値は次のようになる。
ex7 :: (Monad m, HasTime t s) => Wire s () m a Double ex7 = integral 10 . 8 main7 :: IO () main7 = testWire clockSession_ ex7
これを、アロー記法で記述すると以下のようになる。
ex7 :: (Monad m, HasTime t s) => Wire s () m a Double ex7 = proc _ -> do b <- integral 10 -< 8 returnA -< b main7 :: IO () main7 = testWire clockSession_ ex7
100メートルの高さから落下するWire型の値は次のようになる。
ex8 :: (Monad m, HasTime t s, Fractional t) => Wire s () m a t ex8 = integral (100.0) . (10 + (-9.8) * time) main8 :: IO () main8 = testWire clockSession_ ex8
これを、アロー記法で記述すると以下のようになる。
ex8 :: (Monad m, HasTime t s, Fractional t) => Wire s () m a t ex8 = proc _ -> do t <- time -< () b <- integral 100.0 -< 10 + (-9.8) * t returnA -< b main8 :: IO () main8 = testWire clockSession_ ex8
11.4 間隔
5秒間"Yes, we can do."と出力するWire型の値は次のようになる。
ex9 :: (Monad m, HasTime t s) => Wire s () m a String ex9 = for 5 . (pure "Yes, we can do.") main9 :: IO () main9 = testWire clockSession_ ex9
これを、アロー記法で記述すると以下のようになる。
ex9 :: (Monad m, HasTime t s) => Wire s () m a String ex9 = proc _ -> do b <- for 5 -< "Yes, we can do." returnA -< b main9 :: IO () main9 = testWire clockSession_ ex9
文字列ではなく時間の場合には次のようになる。
ex9' :: (Monad m, HasTime t s) => Wire s () m a t ex9' = for 5 . time main9' :: IO () main9' = testWire clockSession_ ex9'
これを、アロー記法で記述すると以下のようになる。
ex9' :: (Monad m, HasTime t s) => Wire s () m a t ex9' = proc _ -> do t <- time -< () b <- for 5 -< t returnA -< b main9' :: IO () main9' = testWire clockSession_ ex9'
5秒経過した後から出力する場合は次のようになる。
ex9'' :: (Monad m, HasTime t s) => Wire s () m a t ex9'' = after 5 . time main9'' :: IO () main9'' = testWire clockSession_ ex9''
これを、アロー記法で記述すると以下のようになる。
ex9'' :: (Monad m, HasTime t s) => Wire s () m a t ex9'' = proc _ -> do t <- time -< () b <- after 5 -< t returnA -< b main9'' :: IO () main9'' = testWire clockSession_ ex9''
11.5 イベント
3秒経過したら"3 seconds."を出力するWire型の値は次のようになる。
ex11 :: (Monad m, HasTime t s) => Wire s () m a String ex11 = asSoonAs . at 3 . (pure "3 seconds.") main11 :: IO () main11 = testWire clockSession_ ex11
これを、アロー記法で記述すると以下のようになる。
ex11 :: (Monad m, HasTime t s) => Wire s () m a String ex11 = proc _ -> do a <- at 3 -< "3 seconds." b <- asSoonAs -< a returnA -< b main11 :: IO () main11 = testWire clockSession_ ex11
文字列に代わって時間を出力させると次のようになる。
ex11' :: (Monad m, HasTime t s) => Wire s () m a t ex11' = asSoonAs . at 3 . time main11' :: IO () main11' = testWire clockSession_ ex11'
これを、アロー記法で記述すると以下のようになる。
ex11' :: (Monad m, HasTime t s) => Wire s () m a t ex11' = proc _ -> do t <- time -< () a <- at 3 -< t b <- asSoonAs -< a returnA -< b main11' :: IO () main11' = testWire clockSession_ ex11'
2秒経過した後に"Yes, we can do."と出力し、4秒経過した後に"No, you cannot do."と出力するWire型の値は次のようになる。
ex12 :: (Monad m, HasTime t s) => Wire s () m a String ex12 = asSoonAs . (at 2 . (pure "Yes, we can do.") <& at 4 . (pure "No, you cannot do.")) main12 :: IO () main12 = testWire clockSession_ ex12
これを、アロー記法で記述すると以下のようになる。
ex12 :: (Monad m, HasTime t s) => Wire s () m a String ex12 = proc _ -> do a <- (<&) proc1 proc2 -< () b <- asSoonAs -< a returnA -< b where proc1 = proc _ -> do b <- at 2 -< "Yes, we can do." returnA -< b proc2 = proc _ -> do b <- at 4 -< "No, you cannot do." returnA -< b main12 :: IO () main12 = testWire clockSession_ ex12
時間に代えると次のようになる。
ex12' :: (Monad m, HasTime t s) => Wire s () m a t ex12' = asSoonAs . (at 2 <& at 4) . time main12' :: IO () main12' = testWire clockSession_ ex12'
これを、アロー記法で記述すると以下のようになる。
ex12' :: (Monad m, HasTime t s) => Wire s () m a t ex12' = proc _ -> do t <- time -< () a <- (<&) (at 2) (at 4) -< t b <- asSoonAs -< a returnA -< b main12' :: IO () main12' = testWire clockSession_ ex12'
11.6 スイッチ
5秒経過するまでは"Yes, we can do."を出力し、その後は"No, you cannot do."を出力するWire型の値は次のようになる。
ex13 :: (Monad m, HasTime t s) => Wire s () m a String ex13 = for 5 . (pure "Yes, we can do.") --> (pure "No, you cannot do.") main13 :: IO () main13 = testWire clockSession_ ex13
これを、アロー記法で記述すると以下のようになる。
ex13 :: (Monad m, HasTime t s) => Wire s () m a String ex13 = proc _ -> do a <- proc1 -< () b <- (-->) (for 5) proc2 -< a returnA -< b where proc1 = proc _ -> do b <- pure "Yes, we can do." -< () returnA -< b proc2 = proc _ -> do b <- pure "No, you cannot do." -< () returnA -< b main13 :: IO () main13 = testWire clockSession_ ex13
文字列を時間に代えると次のようになる。
ex13' :: (Monad m, HasTime t s) => Wire s () m a t ex13' = for 5 . time --> time main13' :: IO () main13' = testWire clockSession_ ex13'
これを、アロー記法で記述すると以下のようになる。
ex13' :: (Monad m, HasTime t s) => Wire s () m a t ex13' = proc _ -> do t <- time -< () b <- (-->) (for 5) time -< t returnA -< b main13' :: IO () main13' = testWire clockSession_ ex13'
イルミネーションのようにしたWire型の値は次のようになる。
ex14 :: (Monad m, HasTime t s, Fractional t) => Wire s () m a String ex14 = for 2 . (pure "Once upon a time...") --> for 3 . (pure "... games were completely imperative...") --> for 2 . (pure "... but then...") --> for 10 . ((pure "Netwire 5! ") <> anim) --> ex14 where anim = holdFor 0.5 . periodic 1 . (pure "Hoo...") <|> (pure "...ray!") main14 :: IO () main14 = testWire clockSession_ ex14
これを、アロー記法で記述すると以下のようになる。
ex14 :: (Monad m, HasTime t s, Fractional t) => Wire s () m a String ex14 = proc _ -> do a <- pure "Once upon a time..." -< () b <- (-->) (for 2) proc1 -< a returnA -< b where proc1 = proc _ -> do a <- pure "... games were completely imperative..." -< () b <- (-->) (for 3) proc2 -< a returnA -< b proc2 = proc _ -> do a <- pure "... but then..." -< () b <- (-->) (for 2) proc3 -< a returnA -< b proc3 = proc _ -> do a <- (<>) (pure "... but then...") anim -< () b <- (-->) (for 10) ex14 -< a returnA -< b anim = proc _ -> do b <- holdFor 0.5 . periodic 1 . (pure "Hoo...") <|> (pure "...ray!") -< () returnA -< bmain14 :: IO () main14 :: IO () main14 = testWire clockSession_ ex14
アロー記法によってWire型の本質的な部分が明らかになったと思う。時間からは、Netwireを用いてのゲームの作成に移る。