machinecell-4.0.0: test/Common/RandomProc.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Arrows #-}
module
Common.RandomProc
where
import Prelude
import Control.Arrow.Machine as P
import Control.Arrow
import qualified Control.Category as Cat
import Control.Applicative
import Control.Monad
import Control.Monad.Trans
import Control.Monad.State
import Control.Monad.Writer
import Test.QuickCheck (Arbitrary, arbitrary, oneof, frequency, sized)
import Data.Maybe (fromJust)
import Data.Monoid (Sum(..), getSum, mappend)
import Data.Foldable (foldMap)
data ProcJoin = PjFst ProcGen | PjSnd ProcGen | PjSum ProcGen
deriving Show
data ProcGen = PgNop |
PgStop |
PgPush ProcGen |
PgPop (ProcGen, ProcGen) ProcJoin |
PgOdd ProcGen |
PgDouble ProcGen |
PgIncl ProcGen |
PgHarf ProcGen
deriving Show
instance
Arbitrary ProcJoin
where
arbitrary = oneof [liftM PjFst arbitrary,
liftM PjSnd arbitrary,
liftM PjSum arbitrary]
instance
Arbitrary ProcGen
where
arbitrary = sized $ \i ->
frequency [(40, rest), (40 + i, content)]
where
rest = return PgNop
content = oneof [
return PgNop,
return PgStop,
liftM PgPush arbitrary,
liftM2 PgPop arbitrary arbitrary,
liftM PgOdd arbitrary,
liftM PgDouble arbitrary,
liftM PgIncl arbitrary,
liftM PgHarf arbitrary
]
type MyProcT = ProcessT (State [Int])
mkProc :: ProcGen
-> MyProcT (Event Int) (Event Int)
mkProc PgNop = Cat.id
mkProc (PgPush next) = mc >>> mkProc next
where
mc = repeatedlyT $
do
x <- await
lift $ modify (\xs -> x:xs)
yield x
mkProc (PgPop (fx, fy) fz) =
mc >>> ((evMap fst >>> fork) &&& (evMap snd >>> fork))
>>> (mkProc fx *** mkProc fy) >>> mkProcJ fz
where
mc = repeatedlyT $
do
x <- await
ys <- lift $ get
case ys
of
[] ->
yield (Just x, Nothing)
(y:yss) ->
do
lift $ put yss
yield (Just x, Just y)
mkProc (PgOdd next) = P.filterEvent cond >>> mkProc next
where
cond x = x `mod` 2 == 1
mkProc (PgDouble next) = arr (fmap $ \x -> [x, x]) >>> fork >>> mkProc next
mkProc (PgIncl next) = arr (fmap (+1)) >>> mkProc next
mkProc (PgHarf next) = arr (fmap (`div`2)) >>> mkProc next
mkProc (PgStop) = stopped
mkProcJ :: ProcJoin -> MyProcT (Event Int, Event Int) (Event Int)
mkProcJ (PjFst pg) = arr fst
mkProcJ (PjSnd pg) = arr snd
mkProcJ (PjSum pg) = proc (evx, evy) ->
returnA -< getSum <$> foldMap (Sum <$>) [evx, evy]
stateProc :: MyProcT (Event a) (Event b) -> [a] -> ([b], [Int])
stateProc pa i =
runState (execWriterT $ runT (\x -> tell [x]) (fit lift pa) i) []
class
TestIn a
where
input :: MyProcT (Event Int) a
class
TestOut a
where
output :: MyProcT a (Event Int)
instance
TestIn (Event Int)
where
input = Cat.id
instance
TestOut (Event Int)
where
output = Cat.id
instance
(TestIn a, TestIn b) => TestIn (a, b)
where
input = mc >>>
((evMap fst >>> fork >>> input) &&& (evMap snd >>> fork >>> input))
where
mc = repeatedly $
do
x <- await
y <- await
yield (Just x, Just y)
instance
(TestOut a, TestOut b) => TestOut (a, b)
where
output = proc (x1, x2) ->
do
y1 <- output -< x1
y2 <- output -< x2
gather -< [y1, y2]
instance
(TestIn a, TestIn b) =>
TestIn (Either a b)
where
input = proc evx ->
do
-- 一個前の値で分岐してみる
b <- dHold True -<
(\x -> x `mod` 2 == 0) <$> evx
if b
then
arr Left <<< input -< evx
else
arr Right <<< input -< evx
instance
(TestOut a, TestOut b) => TestOut (Either a b)
where
output = output ||| output
type MyTestT a b = MyProcT a b -> MyProcT a b -> Bool
mkEquivTest :: (TestIn a, TestOut b) =>
(Maybe (ProcGen, ProcJoin), ProcGen, ProcGen, [Int]) ->
MyTestT a b
mkEquivTest (Nothing, pre, post, l) pa pb =
let
preA = mkProc pre
postA = mkProc post
mkCompared p = preA >>> input >>> p >>> output >>> postA
x = stateProc (mkCompared pa) l
y = stateProc (mkCompared pb) l
in
x == y
mkEquivTest (Just (par, j), pre, post, l) pa pb =
let
preA = mkProc pre
postA = mkProc post
parA = mkProc par
joinA = mkProcJ j
mkCompared p = preA >>> input >>> p >>> output >>> postA
x = stateProc (mkCompared pa) l
y = stateProc (mkCompared pb) l
in
x == y
mkEquivTest2 ::(Maybe (ProcGen, ProcJoin), ProcGen, ProcGen, [Int]) ->
MyProcT (Event Int, Event Int) (Event Int, Event Int) ->
MyProcT (Event Int, Event Int) (Event Int, Event Int) ->
Bool
mkEquivTest2 = mkEquivTest