forsyde-atom-0.3.0.0: Shallow-embedded DSL for modeling cyber-physical systems
Copyright(c) George Ungureanu 2016-2017
LicenseBSD-style (see the file LICENSE)
Maintainerugeorge@kth.se
Stabilityexperimental
Portabilityportable
Safe HaskellSafe
LanguageHaskell2010

ForSyDe.Atom.MoC.DE

Description

The DE library implements a DSL of atoms that operate according to a (safe instance of) the discrete event model of computation, along with helpers and patterns associated with this MoC.

This module exports a reduced interpretation of a DE language, where we assume that each event in a DE signal is persistent, i.e. happened at a discrete instant, and is buffered until a new event occurs. This enables to exploit the "dataflow" host of Streams in a conservative and completely deterministic manner. For an experimental DE language where events are not persistent but instantaneous, which goes along the classical interpretation of DE [Cassandras09] please check ForSyDe.Atom.MoC.DE.React.

Useful pointers:

  • ForSyDe.Atom contains general guidelines for using the API
  • ForSyDe.Atom.MoC documents details about the internals of the MoC layer, the atoms and the basic structure of all process constructors as MoC patterns.
  • ForSyDe.Atom.Utility.Plot contains useful utilities for plotting DE signals.
  • ForSyDe.Atom.MoC.DE.React contains a (possibly non-conservative) DE language where events are treated as non-persistent.
  • the naming convention rules on how to interpret the function names based on their number of inputs and outputs.
Synopsis

Discrete event (DE)

According to the tagged signal model [Lee98], "a discrete-event system is a timed system \(Q\) where for all \(s\in Q\), the tag sytem is order-isomorphic to a subset of the integers. Order-isomorphic means that there exists an order-preserving bijection between the events in and a subset of the integers (or the entire set of integers)."

The discrete event (DE) MoC describes a notion of physical time through its tags, also called timestamps. An important property of the DE tag system is that between any two timestamps \(t_u\) and \(t_v\) there is a finite number of possible timestamps. Based on these observations we can formulate the folowing simplified definition:

The DE MoC
is abstracting the execution semantics of a system where synchronization is discrete (i.e. happens at discrete instants in time) and time-dependent (i.e. is based on an implicit algebra of tags).

There are many variants of discrete event simulators in literature. The execution model covered by the DE implementation in the ForSyDe.Atom.MoC.DE module may be described as a "strictly causal cycle simulator" with no delta-delay nor superdense time. The signals behave as "persistent channels" (similar to an HDL simulator), and processes react instantaneously to any new event. The simplicity of the execution model is ideal for modeling safe DE systems, its monotonic dataflow internals making it somewhat comparable to the conservative discrete event simulators (see [Fujimoto00]). Below you can see an example of a simple DE process, without any behavior extensions:

A variant of the DE MoC where events are instantaneous and non-triggering behavior is implemented in ForSyDe.Atom.MoC.DE.React. Below are stated a few particularities of this DE MoC implementation:

  1. in the terms of [Lee98], our DE MoC is a one-sided system, i.e. time starts from an absolute \(0\). While negative time cannot be represented, signals can be "phase-aligned" with the help of the -&- atom. All signals need to start from timestamp \(0\), and events need to be positioned with their tags in strict ascending order. The checkSignal utility enforces these rules. This restriction is lifted in ForSyDe.Atom.MoC.DE.React.
  2. tags are explicit and a DE event will construct a type around both a tag and a value. Tags represent the start time of the event, the end time being implicit from the start time of the next event. By doing so, we ensure that the time domain is non-disjoint and continuous. This implies that, at any instant in time a DE system describes one specific state.
  3. events are assumed to persist from their time of arrival until the next event arrives or, if there is no incoming event, until infinity. Hence, signals can be interpreted as either persistent channels (e.g. latched wires), or non-blocking buffers of size 1.
  4. a safe delay consists in a prepend -<- (i.e. generating the new value) and a phase shift -&- (i.e. advancing time with a positive integer). This is done in order to both preserve causality and avoid deadlock.
  5. as a consequence a pure DE feedback loop will generate an infinite number of events (strictly preceding each other), since it updates the value after a certain delay, and any input is assumed to go to infinity. Hence all the stateful processes that involve a feedback loop, e.g. state22, moore22, mealy22 are, by design choice, exposing this type of oscillating behavior. For sateful processes that react "instantaneously", one should consider defining a hybrid SY/DE process, see embedSY22.
  6. due to the reactive dataflow natures of the host Streams, DE processes should not to clean up events. Doing so might lead to deadlock wherever any feedback is involved. This means that a new event is created every time a new event arrives, regardless of what value it carries. This means that all values are propagated, justifying our system's conservative approach [Fujimoto00]. DE atoms do not clean signals, however this restriction is lifted in ForSyDe.Atom.MoC.DE.React.
  7. due to the pure and conservative approach, ForSyDe DE simulations, although not very efficient (i.e. suffer from the same drawback as the fist generation of conservative approaches, namey "lookahead creep", see unpublished yet), are completely parallelizable. This is because processes are self-sufficient and do not depend on a global event queue (as compared to other cycle simulators).
  8. any signal from outside needs to be sane ( \(T\) must be a total order) before being injected into a ForSyDe process network. Helper functions are equipped with sanity checkers. Inside a ForSyDe process network, transformations are monotonic, thus output signals are guaranteed to be sane.
  9. since \(T\) is a total order, there is no need for an execution context and we can ignore the formatting of functions in ForSyDe.Atom.MoC, thus \[ \Gamma\vdash\alpha\rightarrow\beta = \alpha\rightarrow\beta \]

data DE t a where Source #

The DE event. It identifies a discrete event signal. The type of the tag system needs to satisfy all of the three properties, as suggested by the type constraints imposed on it:

  • it needs to be a numerical type, to express value 0 (global start) and every representable number needs to have an additive inverse.
  • it needs to be unambiguously comparable (defines a total order).
  • it needs to unambiguously define an equality operation.

Due to these properties not all numerical types can represent DE tags. A typical example of inappropriate representation is Float.

Constructors

DE 

Fields

  • :: (Num t, Ord t, Eq t)
     
  • => { tag :: t

    timestamp

  •    , val :: a

    the value

  •    } -> DE t a
     

Instances

Instances details
(Num t, Ord t, Eq t) => Functor (DE t) Source #

Allows for mapping of functions on a DE event.

Instance details

Defined in ForSyDe.Atom.MoC.DE.Core

Methods

fmap :: (a -> b) -> DE t a -> DE t b #

(<$) :: a -> DE t b -> DE t a #

(Num t, Ord t, Eq t) => Applicative (DE t) Source #

Allows for lifting functions on a pair of DE events.

Instance details

Defined in ForSyDe.Atom.MoC.DE.Core

Methods

pure :: a -> DE t a #

(<*>) :: DE t (a -> b) -> DE t a -> DE t b #

liftA2 :: (a -> b -> c) -> DE t a -> DE t b -> DE t c #

(*>) :: DE t a -> DE t b -> DE t b #

(<*) :: DE t a -> DE t b -> DE t a #

(Num t, Ord t, Eq t) => MoC (DE t) Source #

Implenents the execution semantics for the DE MoC atoms.

Instance details

Defined in ForSyDe.Atom.MoC.DE.Core

Associated Types

type Fun (DE t) a b Source #

type Ret (DE t) b Source #

Methods

(-.-) :: Fun (DE t) a b -> Stream (DE t a) -> Stream (DE t b) Source #

(-*-) :: Stream (DE t (Fun (DE t) a b)) -> Stream (DE t a) -> Stream (DE t b) Source #

(-*) :: Stream (DE t (Ret (DE t) b)) -> Stream (DE t b) Source #

(-<-) :: Stream (DE t a) -> Stream (DE t a) -> Stream (DE t a) Source #

(-&-) :: Stream (DE t a) -> Stream (DE t a) -> Stream (DE t a) Source #

(Num t, Ord t, Eq t, Eq t, Eq a) => Eq (DE t a) Source # 
Instance details

Defined in ForSyDe.Atom.MoC.DE.Core

Methods

(==) :: DE t a -> DE t a -> Bool #

(/=) :: DE t a -> DE t a -> Bool #

(Read a, Read t, Num t, Ord t, Eq t, Eq t) => Read (DE t a) Source #

Reads the string of type v@t as an event DE t v.

Instance details

Defined in ForSyDe.Atom.MoC.DE.Core

Methods

readsPrec :: Int -> ReadS (DE t a) #

readList :: ReadS [DE t a] #

readPrec :: ReadPrec (DE t a) #

readListPrec :: ReadPrec [DE t a] #

(Show a, Show t) => Show (DE t a) Source #

Shows the event with tag t and value v as v@t.

Instance details

Defined in ForSyDe.Atom.MoC.DE.Core

Methods

showsPrec :: Int -> DE t a -> ShowS #

show :: DE t a -> String #

showList :: [DE t a] -> ShowS #

(Plottable a, Show t, Real t, Fractional t, Num t, Ord t, Eq t) => Plot (SignalBase t a) Source #

For plotting DE signals.

Instance details

Defined in ForSyDe.Atom.Utility.Plot

type Ret (DE t) b Source # 
Instance details

Defined in ForSyDe.Atom.MoC.DE.Core

type Ret (DE t) b = b
type Fun (DE t) a b Source # 
Instance details

Defined in ForSyDe.Atom.MoC.DE.Core

type Fun (DE t) a b = a -> b

Aliases & utilities

These are type synonyms and utilities provided for user convenience. They mainly concern the construction and usage of signals.

type SignalBase t a = Stream (DE t a) Source #

Type synonym for a base DE signal as a stream of DE events, where the type of tags has not been determined yet. In designs, it is advised to define a type alias for signals, using an appropriate numerical type for tags, e.g.

import ForSyDe.Atom.MoC.DE hiding (Signal) -- hide provided alias, to use your own

type Signal a = SignalBase Int a

type Signal a = SignalBase TimeStamp a Source #

Convenience alias for a DE signal, where tags are represented using our exported TimeStamp type.

type TimeStamp = DiffTime Source #

Alias for the type representing discrete time. It is inherently quantizable, the quantum being a picosecond ( \(10^{-12}\) seconds), thus it can be considered order-isomorphic with a set of integers, i.e. between any two timestamps there is a finite number of timestamps. Moreover, a timestamp can be easily translated into a rational number representing fractions of a second, so the conversion between timestamps (discrete time) and rationals (analog/continuous time) is straightforward.

This type is used in the explicit tags of the DE MoC (and subsequently the discrete event evaluation engine for simulating the CT MoC).

unit2 :: (Num t, Ord t, Eq t) => ((t, a1), (t, a2)) -> (SignalBase t a1, SignalBase t a2) Source #

Wraps a (tuple of) pair(s) (tag, value) into the equivalent unit signal(s). A unit signal is a signal with one event with the period tag carrying value.

Helpers: unit|unit[2-4].

infinite :: (Num t, Ord t, Eq t) => a -> SignalBase t a Source #

Creates an infinite signal.

until :: (Num t, Ord t, Eq t) => t -> SignalBase t a -> SignalBase t a Source #

Takes the first part of the signal util a given timestamp. The last event of the resulting signal is at the given timestamp and carries the previous value. This utility is useful when plotting a signal, to specify the interval of plotting.

signal :: (Num t, Ord t, Eq t) => [(t, a)] -> SignalBase t a Source #

Transforms a list of tuples (tag, value) into a DE signal. Checks if it is well-formed.

checkSignal :: (Num t, Ord t) => Stream (DE t a) -> Stream (DE t a) Source #

Checks if a signal is well-formed or not, according to the DE MoC interpretation in ForSyDe-Atom.

readSignal :: (Num t, Ord t, Eq t, Read t, Read a) => String -> SignalBase t a Source #

Reads a signal from a string and checks if it is well-formed. Like with the read function from Prelude, you must specify the type of the signal.

>>> readSignal "{ 1@0, 2@2, 3@5, 4@7, 5@10 }" :: Signal Int
{1@0s,2@2s,3@5s,4@7s,5@10s}

Incorrect usage (not covered by doctest):

λ> readSignal "{ 1@0, 2@2, 3@5, 4@10, 5@7 }" :: Signal Int
{1@0s,2@2s,3@5s*** Exception: [MoC.DE] malformed signal
λ> readSignal "{ 1@1, 2@2, 3@5, 4@7, 5@10 }" :: Signal Int
*** Exception: [MoC.DE] signal does not start from global 0

DE process constuctors

These are specific implementations of the atom patterns defined in ForSyDe.Atom.MoC.

Simple

These are mainly direct instantiations of patterns defined in ForSyDe.Atom.MoC, using DE-specific utilities.

delay Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> t

time delay

-> a

initial value

-> SignalBase t a

input signal

-> SignalBase t a

output signal

The delay process "delays" a signal with one event. Instantiates the delay pattern defined in ForSyDe.Atom.MoC.

>>> let s = readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: Signal Int
>>> delay 3 0 s
{0@0s,1@3s,2@5s,3@9s,4@11s,5@12s}

delay' Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> SignalBase t a

signal "borrowing" the initial event

-> SignalBase t a

input signal

-> SignalBase t a

output signal

Similar to the previous, but this is the raw instantiation of the delay pattern from ForSyDe.Atom.MoC. It "borrows" the first event from one signal and appends it at the head of another signal.

>>> let s1 = readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: Signal Int
>>> let s2 = readSignal "{3@0, 4@4, 5@5, 6@8, 7@9}" :: Signal Int
>>> delay' s1 s2
{1@0s,3@2s,4@6s,5@7s,6@10s,7@11s}

comb22 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> (a1 -> a2 -> (b1, b2))

function on values

-> SignalBase t a1

first input signal

-> SignalBase t a2

second input signal

-> (SignalBase t b1, SignalBase t b2)

two output signals

comb processes map combinatorial functions on signals and take care of synchronization between input signals. It instantiates the comb pattern (see comb22 defined in ForSyDe.Atom.MoC).

Constructors: comb[1-4][1-4].

>>> let s1 = infinite 1
>>> let s2 = readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: Signal Int
>>> comb11 (+1) s2
{2@0s,3@2s,4@6s,5@8s,6@9s}
>>> comb22 (\a b-> (a+b,a-b)) s1 s2
({2@0s,3@2s,4@6s,5@8s,6@9s},{0@0s,-1@2s,-2@6s,-3@8s,-4@9s})

reconfig22 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> SignalBase t (a1 -> a2 -> (b1, b2))

signal carrying functions

-> SignalBase t a1

first input signal carrying arguments

-> SignalBase t a2

second input signal carrying arguments

-> (SignalBase t b1, SignalBase t b2)

two output signals

reconfig creates a DE adaptive process where the first signal carries functions and the other carry the arguments. It instantiates the reconfig atom pattern (see reconfig22 defined in ForSyDe.Atom.MoC).

Constructors: reconfig[1-4][1-4].

>>> let sf = signal [(0,(+1)),(2,(*2)),(5,(+1)),(7,(*2))]
>>> let s1 = signal [(0,1),(3,2),(5,3),(9,4)]
>>> reconfig11 sf s1
{2@0,2@2,4@3,4@5,6@7,8@9}

sync2 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> SignalBase t a1

first input signal

-> SignalBase t a2

second input signal

-> (SignalBase t a1, SignalBase t a2)

two output signals

sync synchronizes multiple signals, so that they have the same set of tags, and consequently, the same number of events. It instantiates the comb atom pattern (see comb22 defined in ForSyDe.Atom.MoC).

Constructors: sync[1-4]

>>> let s1 = readSignal "{1@0, 2@2, 3@6, 4@8,  5@9}"  :: Signal Int
>>> let s2 = readSignal "{1@0, 2@5, 3@6, 4@10, 5@12}" :: Signal Int
>>> sync2 s1 s2
({1@0s,2@2s,2@5s,3@6s,4@8s,5@9s,5@10s,5@12s},{1@0s,1@2s,2@5s,3@6s,3@8s,3@9s,4@10s,5@12s})

constant2 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> (b1, b2)

values to be repeated

-> (SignalBase t b1, SignalBase t b2)

generated signals

A signal generator which keeps a value constant. As compared with the SY, it just constructs an infinite signal with constant value (i.e. a signal with one event starting from time 0).

Constructors: constant[1-4].

>>> constant1 2
{2@0}

generate2 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> (b1 -> b2 -> (b1, b2))

function to generate next value

-> ((t, b1), (t, b2))

kernel values tupled with their generation rate.

-> (SignalBase t b1, SignalBase t b2)

generated signals

A signal generator based on a function and a kernel value. It is actually an instantiation of the stated0X constructor (check stated22 defined in ForSyDe.Atom.MoC).

Constructors: generate[1-4].

>>> let (s1,s2) = generate2 (\a b -> (a+1,b+2)) ((3,1),(1,2))
>>> takeS 5 s1
{1@0,2@3,2@4,2@5,3@6}
>>> takeS 7 s2
{2@0,4@1,6@2,8@3,10@4,12@5,14@6}

stated22 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> (b1 -> b2 -> a1 -> a2 -> (b1, b2))

next state function

-> ((t, b1), (t, b2))

initial state values tupled with their initial delay

-> SignalBase t a1

first input signal

-> SignalBase t a2

second input signal

-> (SignalBase t b1, SignalBase t b2)

output signals

stated is a state machine without an output decoder. It is an instantiation of the state MoC constructor (see stated22 defined in ForSyDe.Atom.MoC).

Constructors: stated[1-4][1-4].

>>> let s = readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: Signal Int
>>> takeS 7 $ stated11 (+) (6,1) s
{1@0s,2@6s,3@8s,5@12s,7@14s,8@15s,10@18s}

state22 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> (b1 -> b2 -> a1 -> a2 -> (b1, b2))

next state function

-> ((t, b1), (t, b2))

initial state values tupled with their initial delay

-> SignalBase t a1

first input signal

-> SignalBase t a2

second input signal

-> (SignalBase t b1, SignalBase t b2)

output signals

state is a state machine without an output decoder, and the state non-transparent. It is an instantiation of the state MoC constructor (see state22 defined in ForSyDe.Atom.MoC).

Constructors: state[1-4][1-4].

>>> let s = readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: Signal Int
>>> takeS 7 $ state11 (+) (6,1) s
{2@0s,3@2s,5@6s,7@8s,8@9s,10@12s,12@14s}

moore22 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> (st -> a1 -> a2 -> st)

next state function

-> (st -> (b1, b2))

output decoder

-> (t, st)

initial state: tag and value

-> SignalBase t a1 
-> SignalBase t a2 
-> (SignalBase t b1, SignalBase t b2) 

moore processes model Moore state machines. It is an instantiation of the moore MoC constructor (see moore22 defined in ForSyDe.Atom.MoC).

Constructors: moore[1-4][1-4]

>>> let s = readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: Signal Int
>>> takeS 7 $ moore11 (+) (+1) (6,1) s
{2@0s,3@6s,4@8s,6@12s,8@14s,9@15s,11@18s}

mealy22 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> (st -> a1 -> a2 -> st)

next state function

-> (st -> a1 -> a2 -> (b1, b2))

outpt decoder

-> (t, st)

initial state: tag and value

-> SignalBase t a1 
-> SignalBase t a2 
-> (SignalBase t b1, SignalBase t b2) 

mealy processes model Mealy state machines. It is an instantiation of the mealy MoC constructor (see mealy22 defined in ForSyDe.Atom.MoC).

Constructors: mealy[1-4][1-4]

>>> let s = readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: Signal Int
>>> takeS 7 $ mealy11 (+) (-) (6,1) s
{0@0s,-1@2s,-1@6s,-1@8s,-2@9s,0@12s,2@14s}

Hybrid

Processes that can wrap other MoCs inside a DE execution model.

embedSY22 Source #

Arguments

:: (Signal a1 -> Signal a2 -> (Signal b1, Signal b2))

SY process

-> Signal a1

first input DE signal

-> Signal a2

second input DE signal

-> (Signal b1, Signal b2)

two output DE signals

Embeds a SY process inside a DE environment. Internally, it synchronizes the input signals, translates them to SY, feeds them to a SY process and translates the result back to DE using the same input tags. Seen from outside, this process behaves like a DE process with "instantaneous response", even for feedback loops.

Constructors: embedSY[1-4][1-4].

For the following example, see the difference between its output and the one of stated22

>>> let s = readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: DE.Signal Int
>>> embedSY11 (SY.stated11 (+) 1) s
{1@0s,2@2s,4@6s,7@8s,11@9s}

Interfaces

toSY2 Source #

Arguments

:: (Num t, Ord t, Eq t) 
=> SignalBase t a

first input DE signal

-> SignalBase t b

second input DE signal

-> (Signal t, Signal a, Signal b)

signal carrying timestamps tupled with the two output SY signals

Synchronizes a (set of) DE signal(s) an strips off their explicit tags, outputting the equivalent SY signal(s), tupled with an SY signal carrying the timestamps for the synchronization points.

Constructors: toSY[1-4]

>>> let s1 = DE.infinite 1
>>> let s2 = DE.readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: DE.Signal Int
>>> toSY2 s1 s2
({0s,2s,6s,8s,9s},{1,1,1,1,1},{1,2,3,4,5})

toCT2 Source #

Arguments

:: (Num ts, Real ts, Ord ts, Eq ts, Num tm, Fractional tm, Ord tm) 
=> SignalBase ts (tm -> a)

first input DE signal

-> SignalBase ts (tm -> b)

second input DE signal

-> (SignalBase ts tm a, SignalBase ts tm b)

two output CT signals

Semantic preserving transformation between a (set of) DE signal(s) and the equivalent CT signals. The DE events must carry a function of Time which will be lifted by providing it with CT implicit time semantics.

Constructors: toCT[1-4].

zipx :: (Num t, Ord t, Eq t) => Vector (SignalBase t a) -> SignalBase t (Vector a) Source #

Synchronizes all the signals contained by a vector and zips them into one signal of vectors. It instantiates the zipx skeleton.

>>> let s1 = DE.readSignal "{1@0, 2@2, 3@6, 4@8, 5@9}" :: DE.Signal Int
>>> let s2 = DE.readSignal "{1@0, 2@2, 3@4, 4@8, 5@9}" :: DE.Signal Int
>>> let v1 = V.vector [s1,s1,s2,s2]
>>> v1
<{1@0s,2@2s,3@6s,4@8s,5@9s},{1@0s,2@2s,3@6s,4@8s,5@9s},{1@0s,2@2s,3@4s,4@8s,5@9s},{1@0s,2@2s,3@4s,4@8s,5@9s}>
>>> zipx v1
{<1,1,1,1>@0s,<2,2,2,2>@2s,<2,2,3,3>@4s,<3,3,3,3>@6s,<4,4,4,4>@8s,<5,5,5,5>@9s}

unzipx :: (Num t, Ord t, Eq t) => Integer -> SignalBase t (Vector a) -> Vector (SignalBase t a) Source #

Unzips the vectors carried by a signal into a vector of signals. It instantiates the unzipx skeleton. To avoid infinite recurrence, the user needs to provide the length of the output vector.

>>> let v1 = V.vector [1,2,3,4]
>>> let s1 = DE.signal [(0,v1),(2,v1),(6,v1),(8,v1),(9,v1)] :: DE.Signal (V.Vector Int)
>>> s1
{<1,2,3,4>@0s,<1,2,3,4>@2s,<1,2,3,4>@6s,<1,2,3,4>@8s,<1,2,3,4>@9s}
>>> unzipx 4 s1
<{1@0s,1@2s,1@6s,1@8s,1@9s},{2@0s,2@2s,2@6s,2@8s,2@9s},{3@0s,3@2s,3@6s,3@8s,3@9s},{4@0s,4@2s,4@6s,4@8s,4@9s}>

unzipx' :: (Num t, Ord t, Eq t) => SignalBase t (Vector a) -> Vector (SignalBase t a) Source #

Same as unzipx, but "sniffs" the first event to determine the length of the output vector. Might have unsafe behavior!

>>> let v1 = V.vector [1,2,3,4]
>>> let s1 = DE.signal [(0,v1),(2,v1),(6,v1),(8,v1),(9,v1)] :: DE.Signal (V.Vector Int)
>>> s1
{<1,2,3,4>@0s,<1,2,3,4>@2s,<1,2,3,4>@6s,<1,2,3,4>@8s,<1,2,3,4>@9s}
>>> unzipx' s1
<{1@0s,1@2s,1@6s,1@8s,1@9s},{2@0s,2@2s,2@6s,2@8s,2@9s},{3@0s,3@2s,3@6s,3@8s,3@9s},{4@0s,4@2s,4@6s,4@8s,4@9s}>