{-# LANGUAGE Arrows #-} module Main(main) where import Control.Arrow import Control.Category import Prelude hiding (id, (.)) class ArrowLoop a => ArrowCircuit a where delay :: b -> a b b -- stream map instance data Stream a = Cons a (Stream a) instance Functor Stream where fmap f ~(Cons a as) = Cons (f a) (fmap f as) zipStream :: Stream a -> Stream b -> Stream (a,b) zipStream ~(Cons a as) ~(Cons b bs) = Cons (a,b) (zipStream as bs) unzipStream :: Stream (a,b) -> (Stream a, Stream b) unzipStream abs = (fmap fst abs, fmap snd abs) newtype StreamMap a b = StreamMap (Stream a -> Stream b) unStreamMap (StreamMap f) = f instance Category StreamMap where id = StreamMap id StreamMap f . StreamMap g = StreamMap (f . g) instance Arrow StreamMap where arr f = StreamMap (fmap f) first (StreamMap f) = StreamMap (uncurry zipStream . first f . unzipStream) instance ArrowLoop StreamMap where loop (StreamMap f) = StreamMap (loop (unzipStream . f . uncurry zipStream)) instance ArrowCircuit StreamMap where delay a = StreamMap (Cons a) listToStream :: [a] -> Stream a listToStream = foldr Cons undefined streamToList :: Stream a -> [a] streamToList (Cons a as) = a:streamToList as runStreamMap :: StreamMap a b -> [a] -> [b] runStreamMap (StreamMap f) as = take (length as) (streamToList (f (listToStream as))) -- simple automaton instance data Auto a b = Auto (a -> (b, Auto a b)) instance Category Auto where id = Auto $ \a -> (a, id) Auto f . Auto g = Auto $ \b -> let (c, g') = g b (d, f') = f c in (d, f' . g') instance Arrow Auto where arr f = Auto $ \a -> (f a, arr f) first (Auto f) = Auto $ \(b,d) -> let (c,f') = f b in ((c,d), first f') instance ArrowLoop Auto where loop (Auto f) = Auto $ \b -> let (~(c,d), f') = f (b,d) in (c, loop f') instance ArrowCircuit Auto where delay a = Auto $ \a' -> (a, delay a') runAuto :: Auto a b -> [a] -> [b] runAuto (Auto f) [] = [] runAuto (Auto f) (a:as) = let (b, f') = f a in b:runAuto f' as -- Some simple example circuits -- A resettable counter (first example in several Hawk papers): counter :: ArrowCircuit a => a Bool Int counter = proc reset -> do rec output <- returnA -< if reset then 0 else next next <- delay 0 -< output+1 returnA -< output -- Some other basic circuits from the Hawk library. -- flush: when reset is True, return d for n ticks, otherwise copy value. -- (a variation on the resettable counter) flush :: ArrowCircuit a => Int -> b -> a (b, Bool) b flush n d = proc (value, reset) -> do rec count <- returnA -< if reset then n else max (next-1) 0 next <- delay 0 -< count returnA -< if count > 0 then d else value -- latch: on each tick, return the last value for which reset was True, -- or init if there was none. -- latch :: ArrowCircuit a => b -> a (b, Bool) b latch init = proc (value, reset) -> do rec out <- returnA -< if reset then value else last last <- delay init -< out returnA -< out -- Some tests using the counter test_input = [True, False, True, False, False, True, False, True] test_input2 = zip [1..] test_input -- A test of the resettable counter. main = do print (runStreamMap counter test_input) print (runAuto counter test_input) print (runStreamMap (flush 2 0) test_input2) print (runAuto (flush 2 0) test_input2) print (runStreamMap (latch 0) test_input2) print (runAuto (latch 0) test_input2) -- A step function (cf current in Lustre) step :: ArrowCircuit a => b -> a (Either b c) b step b = proc x -> do rec last_b <- delay b -< getLeft last_b x returnA -< last_b where getLeft _ (Left b) = b getLeft b (Right _) = b