----------------------------------------------------------------------------- -- | -- Module : ForSyDe.Shallow.MoC.CSDF -- Copyright : (c) Ricardo Bonna, KTH/ICT/ES, ForSyDe-Group -- License : BSD-style (see the file LICENSE) -- -- Maintainer : ricardobonna@gmail.com -- Stability : experimental -- Portability : portable -- -- Experimental lib. Further test needed -- ----------------------------------------------------------------------------- module ForSyDe.Shallow.MoC.CSDF ( -- * Sequential Process Constructors -- | Sequential process constructors are used for processes that -- have a state. One of the input parameters is the initial state. delayCSDF, -- * Actors -- | Based on the process constructors in the CSDF-MoC, the -- CSDF-library provides CSDF-actors with single or multiple inputs actor11CSDF, actor12CSDF, actor13CSDF, actor14CSDF, actor21CSDF, actor22CSDF, actor23CSDF, actor24CSDF, actor31CSDF, actor32CSDF, actor33CSDF, actor34CSDF, actor41CSDF, actor42CSDF, actor43CSDF, actor44CSDF ) where import ForSyDe.Shallow.Core ------------------------------------- -- -- -- SEQUENTIAL PROCESS CONSTRUCTORS -- -- -- ------------------------------------- -- | The process constructor 'delaynCSDF' delays the signal n event -- cycles by introducing n initial values at the beginning of the -- output signal. -- -- >>> delayCSDF [3,2,1,0] $ signal [1..5] -- {3,2,1,0,1,2,3,4,5} delayCSDF :: [a] -> Signal a -> Signal a delayCSDF initial_tokens xs = signal initial_tokens +-+ xs ------------------------------------------------------------------------ -- -- CSDF ACTORS -- ------------------------------------------------------------------------ -- > Actors with one output -- | The process constructor 'actor11CSDF' constructs an CSDF actor with -- one input and one output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. -- -- >>> let c1 = (2,1,\[a,b] -> [a + b]) -- >>> let c2 = (2,2,\[a,b] -> [max a b, min a b]) -- >>> let c3 = (2,1,\[a,b] -> [a - b]) -- >>> let s = signal [1..20] -- >>> s -- {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20} -- >>> actor11CSDF [c1,c2,c3] s -- {3,4,3,-1,15,10,9,-1,27,16,15,-1,39} actor11CSDF :: [(Int, Int, [a] -> [b])] -> Signal a -> Signal b actor11CSDF = mapCSDF -- | The process constructor 'actor21CSDF' constructs an CSDF actor with -- two input and one output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. -- -- >>> let c1 = ((2,2),1,\[a,b] [c,d] -> [a+b+c+d]) -- >>> let c2 = ((1,1),2,\ [a] [b] -> [max a b, min a b]) -- >>> let c3 = ((1,3),1,\ [a] [b,c,d] -> [a-b+c-d]) -- >>> let s1 = signal [1..10] -- >>> let s2 = signal [10..] -- >>> actor21CSDF [c1,c2,c3] s1 s2 -- {24,12,3,-10,44,18,7,-12,64} actor21CSDF :: [((Int, Int), Int, [a] -> [b] -> [c])] -> Signal a -> Signal b -> Signal c actor21CSDF = zipWithCSDF -- | The process constructor 'actor31CSDF' constructs an CSDF actor with -- three input and one output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor31CSDF :: [((Int, Int, Int), Int, [a] -> [b] -> [c] -> [d])] -> Signal a -> Signal b -> Signal c -> Signal d actor31CSDF = zipWith3CSDF -- | The process constructor 'actor41CSDF' constructs an CSDF actor with -- four input and one output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor41CSDF :: [((Int, Int, Int, Int), Int, [a] -> [b] -> [c] -> [d] -> [e])] -> Signal a -> Signal b -> Signal c -> Signal d -> Signal e actor41CSDF = zipWith4CSDF -- > Actors with two outputs -- | The process constructor 'actor12CSDF' constructs an CSDF actor with -- one input and two output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor12CSDF :: [(Int, (Int, Int), [a] -> ([b], [c]))] -> Signal a -> (Signal b, Signal c) actor12CSDF s xs = unzipCSDF (outputTokens s) $ mapCSDF (inpOut1n s) xs -- | The process constructor 'actor22CSDF' constructs an CSDF actor with -- two input and two output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. -- -- >>> let c1 = ((2,1), (0,1), \[a,b] [c] -> ([], [a+b+c])) -- >>> let c2 = ((1,3), (2,3), \[a] [b,c,d] -> ([a,b], [b, c, d])) -- >>> actor22CSDF [c1,c2] (signal [1..10]) (signal [11..20]) -- ({3,12,6,16},{14,12,13,14,24,16,17,18,34}) actor22CSDF :: [((Int, Int), (Int, Int), [a] -> [b] -> ([c], [d]))] -> Signal a -> Signal b -> (Signal c, Signal d) actor22CSDF s xs ys = unzipCSDF (outputTokens s) $ zipWithCSDF (inpOut2n s) xs ys -- | The process constructor 'actor32CSDF' constructs an CSDF actor with -- three input and two output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor32CSDF :: [((Int, Int, Int), (Int, Int), [a] -> [b] -> [c] -> ([d], [e]))] -> Signal a -> Signal b -> Signal c -> (Signal d, Signal e) actor32CSDF s as bs cs = unzipCSDF (outputTokens s) $ zipWith3CSDF (inpOut3n s) as bs cs -- | The process constructor 'actor42CSDF' constructs an CSDF actor with -- four input and two output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor42CSDF :: [((Int, Int, Int, Int), (Int, Int), [a] -> [b] -> [c] -> [d] -> ([e], [f]))] -> Signal a -> Signal b -> Signal c -> Signal d -> (Signal e, Signal f) actor42CSDF s as bs cs ds = unzipCSDF (outputTokens s) $ zipWith4CSDF (inpOut4n s) as bs cs ds -- > Actors with three outputs -- | The process constructor 'actor13CSDF' constructs an CSDF actor with -- one input and three output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor13CSDF :: [(Int, (Int, Int, Int), [a] -> ([b], [c], [d]))] -> Signal a -> (Signal b, Signal c, Signal d) actor13CSDF s xs = unzip3CSDF (outputTokens s) $ mapCSDF (inpOut1n s) xs -- | The process constructor 'actor23CSDF' constructs an CSDF actor with -- two input and three output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor23CSDF :: [((Int, Int), (Int, Int, Int), [a] -> [b] -> ([c], [d], [e]))] -> Signal a -> Signal b -> (Signal c, Signal d, Signal e) actor23CSDF s xs ys = unzip3CSDF (outputTokens s) $ zipWithCSDF (inpOut2n s) xs ys -- | The process constructor 'actor33CSDF' constructs an CSDF actor with -- three input and three output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor33CSDF :: [((Int, Int, Int), (Int, Int, Int), [a] -> [b] -> [c] -> ([d], [e], [f]))] -> Signal a -> Signal b -> Signal c -> (Signal d, Signal e, Signal f) actor33CSDF s as bs cs = unzip3CSDF (outputTokens s) $ zipWith3CSDF (inpOut3n s) as bs cs -- | The process constructor 'actor43CSDF' constructs an CSDF actor with -- four input and three output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor43CSDF :: [((Int, Int, Int, Int), (Int, Int, Int), [a] -> [b] -> [c] -> [d] -> ([e], [f], [g]))] -> Signal a -> Signal b -> Signal c -> Signal d -> (Signal e, Signal f, Signal g) actor43CSDF s as bs cs ds = unzip3CSDF (outputTokens s) $ zipWith4CSDF (inpOut4n s) as bs cs ds -- > Actors with four outputs -- | The process constructor 'actor14CSDF' constructs an CSDF actor with -- one input and four output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor14CSDF :: [(Int, (Int, Int, Int, Int), [a] -> ([b], [c], [d], [e]))] -> Signal a -> (Signal b, Signal c, Signal d, Signal e) actor14CSDF s xs = unzip4CSDF (outputTokens s) $ mapCSDF (inpOut1n s) xs -- | The process constructor 'actor24CSDF' constructs an CSDF actor with -- two input and four output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor24CSDF :: [((Int, Int), (Int, Int, Int, Int), [a] -> [b] -> ([c], [d], [e], [f]))] -> Signal a -> Signal b -> (Signal c, Signal d, Signal e, Signal f) actor24CSDF s xs ys = unzip4CSDF (outputTokens s) $ zipWithCSDF (inpOut2n s) xs ys -- | The process constructor 'actor34CSDF' constructs an CSDF actor with -- three input and four output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. -- -- >>> let c1 = ((1,0,1), (1,1,3,0), \[a] _ [b] -> ([b], [succ b], [a, 2*a, 3*a], [])) -- >>> let c2 = ((2,1,1), (0,2,1,1), \[a,b] [c] [d] -> ([], [d, succ d], [a+b], [c])) -- >>> actor34CSDF [c1,c2] (signal [1..10]) (signal [11..20]) (signal ['a'..'k']) -- ({'a','c','e','g'},{'b','b','c','d','d','e','f','f','g','h'},{1,2,3,5,4,8,12,11,7,14,21,17,10,20,30},{11,12,13}) actor34CSDF :: [((Int, Int, Int), (Int, Int, Int, Int), [a] -> [b] -> [c] -> ([d], [e], [f], [g]))] -> Signal a -> Signal b -> Signal c -> (Signal d, Signal e, Signal f, Signal g) actor34CSDF s as bs cs = unzip4CSDF (outputTokens s) $ zipWith3CSDF (inpOut3n s) as bs cs -- | The process constructor 'actor44CSDF' constructs an CSDF actor with -- four input and four output signals. For each firing, the actor behaves -- accordingly to the scenario (a tuple with the number of consumed tokens, -- produced tokens and the function) defined in the list of tuples, given as -- argument, in a cyclic fashion. The length of the list of scenarios gives the -- actor's cycle period. actor44CSDF :: [((Int, Int, Int, Int), (Int, Int, Int, Int), [a] -> [b] -> [c] -> [d] -> ([e], [f], [g], [h]))] -> Signal a -> Signal b -> Signal c -> Signal d -> (Signal e, Signal f, Signal g, Signal h) actor44CSDF s as bs cs ds = unzip4CSDF (outputTokens s) $ zipWith4CSDF (inpOut4n s) as bs cs ds ------------------------------------------------------------------------ -- COMBINATIONAL PROCESS CONSTRUCTORS ------------------------------------------------------------------------ -- | The process constructor 'mapCSDF' takes a list of scenarios, where each -- scenario is a tuple @(c, p, f)@ containing the number of consumed tokens (@c@), -- produced tokens (@p@) and corresponding functions (@f@) that operates on -- a list, and results in an CSDF-process that takes an input signal -- and results in an output signal mapCSDF :: [(Int, Int, [a] -> [b])] -> Signal a -> Signal b mapCSDF [] _ = error "mapCSDF: List of functions must not be empty" mapCSDF (s:ss) xs | c < 0 = error "mapCSDF: Number of consumed tokens must be a non-negative integer" | not $ sufficient_tokens c xs = NullS | otherwise = if length produced_tokens == p then signal produced_tokens +-+ mapCSDF (ss++[s]) (dropS c xs) else error "mapCSDF: Function does not produce correct number of tokens" where (c, p, f) = s consumed_tokens = fromSignal $ takeS c xs produced_tokens = f consumed_tokens -- | The process constructor 'zipWithCSDF' takes a list of scenarios, where each -- scenario is a tuple @(c, p, f)@ containing the number of consumed tokens (@c@), -- produced tokens (@p@) and corresponding functions (@f@) -- that operates on two lists, and results in an CSDF-process that takes two -- input signals and results in an output signal zipWithCSDF :: [((Int, Int), Int, [a] -> [b] -> [c])] -> Signal a -> Signal b -> Signal c zipWithCSDF [] _ _ = error "zipWithCSDF: List of functions must not be empty" zipWithCSDF (s:ss) as bs | c1 < 0 || c2 < 0 = error "zipWithCSDF: Number of consumed tokens must be a non-negative integer" | (not $ sufficient_tokens c1 as) || (not $ sufficient_tokens c2 bs) = NullS | otherwise = if length produced_tokens == p then signal produced_tokens +-+ zipWithCSDF (ss++[s]) (dropS c1 as) (dropS c2 bs) else error "zipWithCSDF: Function does not produce correct number of tokens" where (c, p, f) = s (c1, c2) = c consumed_tokens_as = fromSignal $ takeS c1 as consumed_tokens_bs = fromSignal $ takeS c2 bs produced_tokens = f consumed_tokens_as consumed_tokens_bs -- | The process constructor 'zipWith3CSDF' takes a list of scenarios, where each -- scenario is a tuple @(c, p, f)@ containing the number of consumed tokens (@c@), -- produced tokens (@p@) and corresponding functions (@f@) -- that operates on three lists, and results in an SDF-process that takes three -- input signals and results in an output signal zipWith3CSDF :: [((Int, Int, Int), Int, [a] -> [b] -> [c] -> [d])] -> Signal a -> Signal b -> Signal c -> Signal d zipWith3CSDF [] _ _ _ = error "zipWith3CSDF: List of functions must not be empty" zipWith3CSDF (s:ss) as bs cs | c1 < 0 || c2 < 0 || c3 < 0 = error "zipWith3CSDF: Number of consumed tokens must be a non-negative integer" | (not $ sufficient_tokens c1 as) || (not $ sufficient_tokens c2 bs) || (not $ sufficient_tokens c3 cs) = NullS | otherwise = if length produced_tokens == p then signal produced_tokens +-+ zipWith3CSDF (ss++[s]) (dropS c1 as) (dropS c2 bs) (dropS c3 cs) else error "zipWith3CSDF: Function does not produce correct number of tokens" where (c, p, f) = s (c1, c2, c3) = c consumed_tokens_as = fromSignal $ takeS c1 as consumed_tokens_bs = fromSignal $ takeS c2 bs consumed_tokens_cs = fromSignal $ takeS c3 cs produced_tokens = f consumed_tokens_as consumed_tokens_bs consumed_tokens_cs -- | The process constructor 'zipWith4CSDF' takes a list of scenarios, where each -- scenario is a tuple @(c, p, f)@ containing the number of consumed tokens (@c@), -- produced tokens (@p@) and corresponding functions (@f@) that -- operates on three lists, and results in an CSDF-process that takes -- three input signals and results in an output signal zipWith4CSDF :: [((Int, Int, Int, Int), Int, [a] -> [b] -> [c] -> [d] -> [e])] -> Signal a -> Signal b -> Signal c -> Signal d -> Signal e zipWith4CSDF [] _ _ _ _ = error "zipWith4CSDF: List of functions must not be empty" zipWith4CSDF (s:ss) as bs cs ds | c1 < 0 || c2 < 0 || c3 < 0 || c4 < 0 = error "zipWith4CSDF: Number of consumed tokens must be a non-negative integer" | (not $ sufficient_tokens c1 as) || (not $ sufficient_tokens c2 bs) || (not $ sufficient_tokens c3 cs) || (not $ sufficient_tokens c4 ds) = NullS | otherwise = if length produced_tokens == p then signal produced_tokens +-+ zipWith4CSDF (ss++[s]) (dropS c1 as) (dropS c2 bs) (dropS c3 cs) (dropS c4 ds) else error "zipWith4CSDF: Function does not produce correct number of tokens" where (c, p, f) = s (c1, c2, c3, c4) = c consumed_tokens_as = fromSignal $ takeS c1 as consumed_tokens_bs = fromSignal $ takeS c2 bs consumed_tokens_cs = fromSignal $ takeS c3 cs consumed_tokens_ds = fromSignal $ takeS c4 ds produced_tokens = f consumed_tokens_as consumed_tokens_bs consumed_tokens_cs consumed_tokens_ds ------------------------------------------------------------------------ -- unzipCSDF Processes ------------------------------------------------------------------------ unzipCSDF :: [(Int, Int)] -> Signal ([a], [b]) -> (Signal a, Signal b) unzipCSDF [] _ = (NullS, NullS) unzipCSDF _ NullS = (NullS, NullS) unzipCSDF ((p1, p2) : ps) ((s1, s2) :- ss) | length s1 /= p1 || length s2 /= p2 = error "unzipCSDF: Process does not produce correct number of tokens" | otherwise = (signal s1 +-+ sr1, signal s2 +-+ sr2) where (sr1, sr2) = unzipCSDF (ps ++ [(p1, p2)]) ss unzip3CSDF :: [(Int, Int, Int)] -> Signal ([a], [b], [c]) -> (Signal a, Signal b, Signal c) unzip3CSDF [] _ = (NullS, NullS, NullS) unzip3CSDF _ NullS = (NullS, NullS, NullS) unzip3CSDF ((p1, p2, p3) : ps) ((s1, s2, s3) :- ss) | length s1 /= p1 || length s2 /= p2 || length s3 /= p3 = error "unzip3CSDF: Process does not produce correct number of tokens" | otherwise = (signal s1 +-+ sr1, signal s2 +-+ sr2, signal s3 +-+ sr3) where (sr1, sr2, sr3) = unzip3CSDF (ps ++ [(p1, p2, p3)]) ss unzip4CSDF :: [(Int, Int, Int, Int)] -> Signal ([a], [b], [c], [d]) -> (Signal a, Signal b, Signal c, Signal d) unzip4CSDF [] _ = (NullS, NullS, NullS, NullS) unzip4CSDF _ NullS = (NullS, NullS, NullS, NullS) unzip4CSDF ((p1, p2, p3, p4) : ps) ((s1, s2, s3, s4) :- ss) | length s1 /= p1 || length s2 /= p2 || length s3 /= p3 || length s4 /= p4 = error "unzip4CSDF: Process does not produce correct number of tokens" | otherwise = (signal s1 +-+ sr1, signal s2 +-+ sr2, signal s3 +-+ sr3, signal s4 +-+ sr4) where (sr1, sr2, sr3, sr4) = unzip4CSDF (ps ++ [(p1, p2, p3, p4)]) ss ------------------------------------------------------------------------ -- -- Helper functions (not exported!) -- ------------------------------------------------------------------------ sufficient_tokens :: (Num a, Eq a, Ord a) => a -> Signal t -> Bool sufficient_tokens 0 _ = True sufficient_tokens _ NullS = False sufficient_tokens n (_:-xs) = if n < 0 then error "sufficient_tokens: n must not be negative" else sufficient_tokens (n-1) xs outputTokens :: [(a, b, c)] -> [b] outputTokens [] = [] outputTokens ((_, b, _):xs) = b : outputTokens xs inpOut1n :: [(it, ot, [a] -> y)] -> [(it, Int, [a] -> [y])] inpOut1n [] = [] inpOut1n ((it, _, f):xs) = (it, 1, \a -> [f a]) : inpOut1n xs inpOut2n :: [(it, ot, [a] -> [b] -> y)] -> [(it, Int, [a] -> [b] -> [y])] inpOut2n [] = [] inpOut2n ((it, _, f):xs) = (it, 1, \a b -> [f a b]) : inpOut2n xs inpOut3n :: [(it, ot, [a] -> [b] -> [c] -> y)] -> [(it, Int, [a] -> [b] -> [c] -> [y])] inpOut3n [] = [] inpOut3n ((it, _, f):xs) = (it, 1, \a b c -> [f a b c]) : inpOut3n xs inpOut4n :: [(it, ot, [a] -> [b] -> [c] -> [d] -> y)] -> [(it, Int, [a] -> [b] -> [c] -> [d] -> [y])] inpOut4n [] = [] inpOut4n ((it, _, f):xs) = (it, 1, \a b c d -> [f a b c d]) : inpOut4n xs ------------------------------------------------------------------------ -- -- Test of Library (not exported) -- ------------------------------------------------------------------------ {- --------------------------------------------------------- -- test1: CSDF graph from the paper Cyclo-Static Dataflow --------------------------------------------------------- test1 :: Num a => Signal a test1 = s3 where s3 = delayCSDF [1,1] s2 s2 = v2 s1 s1 = v1 s4 s4 = v3 s3 v1 = actor11CSDF [(1, 1, \[a] -> [a]), (1, 0, \_ -> []), (1, 0, \_ -> [])] v2 = actor11CSDF [(1, 0, \_ -> []), (1, 2, \[a] -> [a, 2*a])] v3 = actor11CSDF [(1, 3, \[a] -> [a, 2*a, 3*a])] -- Shows the first 10 values of the output (signal s3) test1out = takeS 10 test1 -- Expected answer: {1,1,1,2,2,4,4,8,8,16} --------------------------------------------------------- -- test2: actor22CSDF test --------------------------------------------------------- test2 :: Num a => Signal a -> Signal a -> (Signal a, Signal a) test2 = actor22CSDF s where s = [((2,1), (0,1), \[a,b] [c] -> ([], [a+b+c])), ((1,3), (2,3), \[a] [b,c,d] -> ([a,b], [b, c, d]))] -- Shows the output for the given inputs test2out = test2 (signal [1..10]) (signal [11..20]) -- Expected answer: ({3,12,6,16},{14,12,13,14,24,16,17,18,34}) --------------------------------------------------------- -- test3: actor34CSDF test --------------------------------------------------------- test3 :: (Num a, Enum b) => Signal a -> Signal a -> Signal b -> (Signal b, Signal b, Signal a, Signal a) test3 = actor34CSDF s where s = [((1,0,1), (1,1,3,0), \[a] _ [b] -> ([b], [succ b], [a, 2*a, 3*a], [])), ((2,1,1), (0,2,1,1), \[a,b] [c] [d] -> ([], [d, succ d], [a+b], [c]))] test3out = test3 (signal [1..10]) (signal [11..20]) (signal ['a'..'k']) -- Expected answer: ({'a','c','e','g'},{'b','b','c','d','d','e','f','f','g','h'}, -- {1,2,3,5,4,8,12,11,7,14,21,17,10,20,30},{11,12,13}) -}