package ListN( ListN, cons, (:>), nil, map, append, concat, genList, genListN, genWith, replicate, foldr, foldr1, foldl, foldl1, fold, head, tail, zipWith, zipWith3, zipWithAny, zipWithAny3, zipAny, unzip, zip, zip3, zip4, rotate, rotateR, reverse, last, init, elem, mapM, mapM_, zipWithM, zipWith3M, zipWithM_, genWithM, replicateM, sequence, foldM, foldlM, foldrM, (!!), select, update, transpose, transposeLN, scanr, sscanr, scanl, sscanl, all, any, take, toList, toListN, mapAccumL, mapAccumR, mapPairs, joinActions, joinRules, newListN ) where import List import Vector infixr 8 :> --@ \subsubsection{ListN} --@ --@ \index{ListN@\te{ListN} (type)|textbf} --@ --@ {\bf Package name} --@ --@ import ListN :: * ; --@ --@ {\bf Description} --@ --@ ListN is an alternative implementation of Vector which is --@ preferred for list processing functions, such as head, tail, map, --@ fold, etc. All Vector functions are available, by substituting --@ ListN for Vector. See the Vector docuemntation (\ref{lib-vector}) --@ for details. If the implementation requires random access to --@ items in the list, the Vector construct is recommended. Using --@ ListN where Vectors is recommended (and visa-versa) can lead to --@ very long static elaboration times. --@ --@ The {\te{ListN}} package defines an abstract data type which is --@ a listN of a specific length. Functions which create and operate --@ on this type are also defined within this package. --@ Because it is abstract, there are no constructors available for this type --@ (like {\te{Cons}} and {\te{Nil}} for the {\te{List}} type). --@ \BBS --@ struct ListN\#(vsize,a\_type) --@ {\rm{\emph{$\cdots$ abstract $\cdots$}}} --@ \EBS --@ --@ Here, the type variable {\qbs{a\_type}} represents the type of the --@ contents of the listN --@ while type variable {\qbs{vsize}} represents the length of the --@ ListN. data (ListN :: # -> * -> *) n a = L (List a) deriving (Eq) -- can't derive PrimSelectable, PrimUpdateable because -- they take more than one type argument unL :: ListN n a -> List a unL (L xs) = xs --X --X A listN can be turned into bits if the individual elements can be turned --X into bits. When packed and unpacked, the zeroth element of the --X listN is stored in the least --X significant bits. The size of the resulting bits is given by --X $ tsize = vsize * {\tt sizeof}( a\_type )$ which is specified in the --X provisos. --X \begin{libverbatim} --X instance Bits #( ListN#(vsize, a_type), tsize) --X provisos (Bits#(a_type, sizea), Mul#(vsize, sizea, tsize)); --X \end{libverbatim} instance (Bits a sa, Mul n sa nsa) => Bits (ListN n a) nsa where pack (L bs) = flatN 0 (List.map pack bs) unpack bs = L (List.map unpack (grabN 0 (valueOf n * valueOf sa) bs)) --X --X ListNs can be compared for equality if the elements can. --X \begin{libverbatim} --X instance Eq #( ListN#(vsize, a_type) ) --X provisos( Eq#( a_type ) ) ; --X \end{libverbatim} {- flatN :: (Add k x m) => Integer -> List (Bit k) -> Bit m flatN n Nil = 0 flatN n (Cons b bs) = (zeroExtend b << fromInteger (vsize * valueOf k)) | flatN (vsize+1) bs -} flatN :: Integer -> List (Bit k) -> Bit m flatN _ Nil = 0 flatN n (Cons b bs) = (b[(valueOf k - 1):0] << (n * valueOf k)) | flatN (n+1) bs grabN :: Integer -> Integer -> Bit m -> List (Bit k) grabN i n bs = if i >= n then Nil else letseq i' = i + valueOf k x = bs[(i'-1) : i] in Cons x (grabN i' n bs) ------------------------------------------------------------------------------ --X \begin{itemize} --X \item{\bf Creating and Generating ListNs} --X --X There are no {\blue} constructors available for this abstract type --X (and hence no pattern-matching is available for this type) --X but the following ordinary functions may be used to construct values of --X the \te{ListN} type. --X --X Generate a ListN with undefined elements, typically used when --X ListNs are declared. --X \index{newListN@\te{newListN} (\te{ListN} function)} --X \begin{libverbatim} --X ListN#(vsize, a_type) newListN ; --X \end{libverbatim} newListN :: ListN n a newListN = replicate _ --X Generate a ListN containing Integers 0 through N-1, --X element[0] will have value 0. --X \index{genListN@\te{genListN} (\te{ListN} function)} --X \begin{libverbatim} --X ListN#(vsize, Integer) genListN; --X \end{libverbatim} genListN :: ListN n Integer genListN = L (upto 0 (valueOf n - 1)) genList :: ListN n Integer genList = genListN --X Generate a ListN of elements by replicating --X the given argument. --X \index{genWith@\te{replicate} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize, a_type) replicate(a_type c); --X \end{libverbatim} replicate :: a -> ListN n a replicate c = map (const c) genList --X Generate a ListN of elements by applying the --X given function to 0 through N-1. --X \index{genWith@\te{genWith} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize, a_type) genWith(function a_type func(Integer x1)); --X \end{libverbatim} genWith :: (Integer -> a) -> ListN n a genWith f = map f genList --X --X Two list-like constructs are given for ListNs, {\tt cons} and {\tt --X nil}; {\tt nil} defines a zero-sized listN, while {\tt cons} adds --X an element to a listN creating a listN one element larger. The --X new element will be at the 0th position. --X \index{cons@\te{cons} (\te{ListN} function for construction)} --X \begin{libverbatim} --X function ListN#(vsize1,a_type) cons (a_type elem, ListN#(vsize,a_type) vect) --X provisos (Add#(1, vsize, vsize1)); --X \end{libverbatim} cons :: (Add 1 n n1) => a -> ListN n a -> ListN n1 a cons x (L xs) = L (Cons x xs) --X@ A more convenient (right associative) operator for Cons (not available in BSV). --X@ \begin{libverbatim} --X@ function ListN#(vsize1,a_type) (:>) (a_type x, ListN#(vsize,a_type) xs) --X@ provisos (Add#(1, n, n1)); --X@ \end{libverbatim} (:>) :: (Add 1 n n1) => a -> ListN n a -> ListN n1 a (:>) x (L xs) = L (Cons x xs) --X --X \index{nil@\te{nil} (\te{ListN} function for construction)} --X \begin{libverbatim} --X ListN#(0, a_type) nil; --X \end{libverbatim} nil :: ListN 0 a nil = L Nil --X --X Append two ListNs, returning the combined ListN. --X \index{append@\te{append} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,a_type) append (ListN#(v0size,a_type) vecta, --X ListN#(v1size,a_type) vectb ) --X provisos (Add#(v0size, v1size, vsize)); --X \end{libverbatim} append :: (Add m n mn) => ListN m a -> ListN n a -> ListN mn a append (L xs) (L ys) = L (List.append xs ys) --X Append many listNs -- a \te{ListN} of \te{ListN}s into one \te{ListN} --X \index{concat@\te{concat} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(mvsize,a_type) concat (ListN#(m,ListN#(vsize,a_type)) xss) --X provisos (Mul#(m, n, mvsize)); --X \end{libverbatim} concat :: (Mul m n mn) => ListN m (ListN n a) -> ListN mn a concat (L xs) = L (List.concat (List.map unL xs)) ------------------------------------------------------------------------------ --X \item{\bf Extracting Elements and Sub-ListNs} --X --X --X In BSV, the square-bracket notation is available to extract an --X element from a ListN, but only during compile-time elaboration. Use the --X select or update functions for runtime access of ListNs. --X \begin{libverbatim} --X instance PrimSelectable #(ListN#(vsize,a_type), Integer, a_type); --X \end{libverbatim} instance PrimSelectable (ListN n a) a where primSelectFn pos (L xs) = primSelectFn pos xs instance PrimUpdateable (ListN n a) a where primUpdateFn pos (L xs) n x = L (primUpdateFn pos xs n x) --X@ Get the element at a certain position. --X@ \index{(!!)@\te{(!!)} (\te{ListN} function)} --X@ \begin{libverbatim} --X@ function a (!!)(ListN#(vsize,a_type) xs, Integer n); --X@ \end{libverbatim} (!!) :: ListN n a -> Integer -> a (!!) (L xs) i = (List.!!) xs i --X The select function is similar to subscript notation {\tt ([i])}, but it can --X generate a multiplexor for runtime access. --X \index{select@\te{select} (\te{ListN} function)} --X \begin{libverbatim} --X function a_type select(ListN#(vsize,a_type) vect, idx_type index ) --X provisos (Eq#(idx_type), Literal#(idx_type)); --X \end{libverbatim} select :: (PrimIndex ix dx) => ListN n a -> ix -> a select = primSelectFn (getStringPosition "") --X Update an element in a listN. --X \index{update@\te{update} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,a_type) update( ListN#(vsize,a_type) vectIn, --X idx_type index, --X a_type newElem) --X provisos (Eq#(idx_type), Literal#(idx_type)); --X \end{libverbatim} update :: (PrimIndex ix dx) => ListN n a -> ix -> a -> ListN n a update = primUpdateFn (getStringPosition "") --X Functions are provided which extract the first (head) element or --X the last element of a listN. --X \index{head@\te{head} (\te{ListN} function)} --X \begin{libverbatim} --X function a_type head (ListN#(vsize,a_type) vect) --X provisos (Add#(1, xxx, vsize)); // vsize >= 1 --X \end{libverbatim} head :: (Add 1 m n) => ListN n a -> a head (L (Cons x _)) = x --X \index{last@\te{last} (\te{ListN} function)} --X \begin{libverbatim} --X function a_type last (ListN#(vsize,a_type) vect); --X provisos (Add#(1, xxx, vsize)); // vsize >= 1 --X \end{libverbatim} last :: (Add 1 m n) => ListN n a -> a last (L xs) = List.last xs --X --X Other functions can remove the head or last element of a --X ListN leaving its tail or initial part in a smaller --X ListN. --X \index{tail@\te{tail} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,a_type) tail (ListN#(vsize1,a_type) xs) --X provisos (Add#(1, vsize, vsize1)); --X \end{libverbatim} tail :: (Add 1 m n) => ListN n a -> ListN m a tail (L (Cons _ xs)) = L xs --X \index{init@\te{init} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,a_type) init (ListN#(vsize1,a_type) xs) --X provisos (Add#(1, vsize, vsize1)) --X \end{libverbatim} init :: (Add 1 m n) => ListN n a -> ListN m a init (L xs) = L (List.init xs) --X Take a number of elements from a ListN starting from index 0. --X \index{take@\te{take} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize2,a_type) take (ListN#(vsize,a_type) vect) --X provisos (Add#(vsize2,xxx,vsize)); // vsize2 <= vsize --X \end{libverbatim} take :: (Add m k n) => ListN n a -> ListN m a take (L xs) = L (List.take (valueOf m) xs) --------------------------------------------------------------------------------- --X \item{\bf Combining ListNs with Zip} --X --X The family of ``zip'' functions takes two or more ListNs and --X combines them into one ListN of \te{Tuples}. Several --X variations are provided for different resulting \te{Tuple}s, as --X well as support for mis-matched ListN sizes. --X --X@ Combine two ListNs into one ListN of pairs (2-tuples). --X \index{zip@\te{zip} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,Tuple2 #(a_type, b_type)) --X zip ( ListN#(vsize,a_type) vecta, ListN#(vsize,b) vectb ) ; --X \end{libverbatim} zip :: ListN n a -> ListN n b -> ListN n (a,b) zip (L xs) (L ys) = L (List.zip xs ys) --X@ Combine three ListNs into one ListN of tuples. --X \index{zip@\te{zip} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,Tuple3 #(a_type, b_type, c_type)) --X zip3 (ListN#(vsize,a_type) vecta, --X ListN#(vsize,b_type) vectb, --X ListN#(vsize,c_type) vectc ); --X \end{libverbatim} zip3 :: ListN n a -> ListN n b -> ListN n c -> ListN n (a, b, c) zip3 (L xs) (L ys) (L zs) = L (List.zip3 xs ys zs) --X@ Combine four ListNs into one ListN of tuples. --X \index{zip@\te{zip} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,Tuple4 #(a_type, b_type, c_type, d_type)) --X zip4 ( ListN#(vsize,a_type) vecta, --X ListN#(vsize,b_type) vectb, --X ListN#(vsize,c_type) vectc, --X ListN#(vsize,d_type) vectd ); --X \end{libverbatim} zip4 :: ListN n a -> ListN n b -> ListN n c -> ListN n d -> ListN n (a, b, c, d) zip4 (L xs) (L ys) (L zs) (L ws) = L (List.zip4 xs ys zs ws) --X Combine two ListNs into one ListN of pairs (2-tuples); result --X is as long as the smaller listN. --X \index{zipAny@\te{zipAny} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,Tuple2 #(a_type, b_type)) --X zipAny ( ListN#(m,a_type) xs, --X ListN#(n,b_type) ys); --X provisos (Max#(m, vsize, m), Max#(n, vsize, n)); --X \end{libverbatim} zipAny :: (Max m mn m, Max n mn n) => ListN m a -> ListN n b -> ListN mn (a,b) zipAny = zipWithAny (\x y -> (x,y)) --X Separate a ListN of pairs into a pair of two ListNs. --X \index{unzip@\te{unzip} (\te{ListN} function)} --X \begin{libverbatim} --X function Tuple2#(ListN#(vsize,a_type), ListN#(vsize,b_type)) --X unzip ( ListN#(vsize,Tuple2 #(a_type, b_type)) vectab ); --X \end{libverbatim} unzip :: ListN n (a, b) -> (ListN n a , ListN n b) unzip (L l) = letseq (as, bs) = List.unzip l in (L as, L bs) -------------------------------------------------------------------------------- --X \item{\bf Mapping Functions over ListNs} --X --X A function can be applied to all elements of a ListN, using --X high-order functions such as {\tt map}. These functions take, as --X an argument, a which is applied to the elements --X of the ListN. --X --X Map a function over a ListN, returning a new ListN of results. --X \index{map@\te{map} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,b_type) map ( function b_type func(a_type x), --X ListN#(vsize,a_type) vect ); --X \end{libverbatim} --X For examples, consider the following code example which applies --X the {\tt zeroExtends} function to each element of alistN into a --X new ListN. --X \begin{libverbatim} --X ListN#(13,Bit#(5)) alistN; --X ListN#(13,Bit#(10)) resultlistN; --X ... --X resultlistN = map( zeroExtend, alistN ) ; --X \end{libverbatim} map :: (a -> b) -> ListN n a -> ListN n b map f (L xs) = L (List.map f xs) --X The ``fold'' family of functions reduces a listN by applying a --X function over all its elements. --X That is, given a --X listN of {\tt a\_type}, $V_0, V_1, V_2, ..., V_{n-1}$, a seed of --X type {\tt b\_type}, and a function {\tt func}, the reduction for --X foldr is given by --X \[ func( V_0, func(V_{1}, ... , func ( V_{n-2} , func( V_{n-1}, seed) ))) ; \] --X Note that foldr start processing from the right, the --X highest index position to the lowest, while {\tt foldl} starts --X from the lowest index (zero), i.e., --X \[ func( ... ( func( func(seed, V_0), V_1), ... ) V_{n-1} ) \] --X \index{foldr@\te{foldr} (\te{ListN} function)} --X \begin{libverbatim} --X function b_type foldr(b_type function func(a_type x, b_type y), --X b_type seed, --X ListN#(vsize,a_type) vect); --X \end{libverbatim} foldr :: (a -> b -> b) -> b -> ListN n a -> b foldr f z (L xs) = List.foldr f z xs --X@ Reduction (from the left) over a ListN. --X \index{foldl@\te{foldl} (\te{ListN} function)} --X \begin{libverbatim} --X function b_type foldl (b_type function func(b_type y, a_type x), --X b_type seed, --X ListN#(vsize,a_type) vect); --X \end{libverbatim} foldl :: (b -> a -> b) -> b -> ListN n a -> b foldl f z (L xs) = List.foldl f z xs --X In places where a fold operation over an empty ListN does not --X make any sense, it is best to use the {\tt foldr1} or {\tt foldl1} --X version of these functions, since these can only be used for --X non-zero sized listNs. --X \index{foldr1@\te{foldr1} (\te{ListN} function)} --X \begin{libverbatim} --X function a_type foldr1 (a_type function func(a_type x, a_type y), --X ListN#(vsize,a_type) vect) --X provisos (Add#(1, xxx, vsize)); // ListN has at least 1 element --X \end{libverbatim} foldr1 :: (Add 1 m n) => (a -> a -> a) -> ListN n a -> a foldr1 f (L xs) = List.foldr1 f xs --X@ Reduction (from the left) over a non-empty ListN --X \index{foldl1@\te{foldl1} (\te{ListN} function)} --X \begin{libverbatim} --X function a_type foldl1 (a_type function func(a_type y, a_type x), --X ListN#(vsize,a_type) vect) --X provisos (Add#(1, xxx, vsize)); // ListN has at least 1 element --X \end{libverbatim} foldl1 :: (Add 1 m n) => (a -> a -> a) -> ListN n a -> a foldl1 f (L xs) = List.foldl1 f xs --X The {\tt fold} function performs a reduction over a non-empty --X listN, but processing is accomplished in a binary tree-like structure. --X Hence the depth or delay through the resulting function will be --X $O(log_2( vsize ) $ rather than $O( vsize ) $. --X \index{fold@\te{fold} (\te{ListN} function)} --X \begin{libverbatim} --X function a_type fold (a_type function func(a_type y, a_type x), --X ListN#(vsize,a_type) vect ) --X provisos (Add#(1, xxx, vsize)); // ListN has at least 1 element --X \end{libverbatim} fold :: (Add 1 n1 n) => (a -> a -> a) -> ListN n a -> a fold f (L xs) = List.fold f xs --X The ``scan'' family of functions applies a function over a listN, --X creating a new listN result. --X That is, given a --X listN of {\tt a\_type}, $V_0, V_1, ..., V_{n-1}$, an initial --X value {\tt initb} of --X type {\tt b\_type}, and a function {\tt func}, application of the --X {\tt scanr} functions creates a new listN $W$, where --X --X \begin{eqnarray*} --X W_n & = & init ; \\ --X W_{n-1} & = & func( V_{n-1}, W_n ) ; \\ --X W_{n-2} & = & func( V_{n-2}, W_{n-1} ) ; \\ --X ... & & \\ --X W_1 & = & func( V_{1}, W_{2} ) ; \\ --X W_0 & = & func( V_0, W_1 ) ; \\ --X \end{eqnarray*} --X --X Note that the {\tt scanr} processes elements from the right, the --X highest index position --X to the lowest, and fill the resulting ListN in the same --X way. The {\tt sscanr} function drops the $W_n$ element from the --X result. --X \index{scanr@\te{scanr} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize1,b_type) --X scanr(function b_type func(a_type x1, b_type x2), --X b_type initb, --X ListN#(vsize,a_type) vect) --X provisos (Add#(1, vsize, vsize1)); --X \end{libverbatim} scanr :: (Add 1 n n1) => (a -> b -> b) -> b -> ListN n a -> ListN n1 b scanr f q (L xs) = L (List.scanr f q xs) --X \index{sscanr@\te{sscanr} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,b_type) --X sscanr( function b_type func(a_type x1, b_type x2), --X b_type initb, --X ListN#(vsize,a_type) vect ); --X \end{libverbatim} sscanr :: (a -> b -> b) -> b -> ListN n a -> ListN n b sscanr f q (L xs) = L (List.sscanr f q xs) --X The {\tt scanl} function creates the resulting ListN in a --X similar way as {\tt scanr} except that the processing happens --X from the zeroth element up to the nth element. --X --X \begin{eqnarray*} --X W_0 & = & init ; \\ --X W_1 & = & func( V_0, W_0 ) ; \\ --X W_2 & = & func( V_1, W_1 ) ; \\ --X ... & & \\ --X W_{n-1} & = & func( V_{n-2}, W_{n-2} ) ; \\ --X W_n & = & func( V_{n-1}, W_{n-1} ) ; \\ --X \end{eqnarray*} --X --X The {\tt sscanl} function drops the first result, $init$, shifting --X the result index by one. --X \index{scanl@\te{scanl} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize1,a_type) --X scanl( function a_type func(a_type x1, b_type x2), --X a_type q, --X ListN#(vsize,b_type) vect) --X provisos (Add#(1, vsize, vsize1)); --X \end{libverbatim} scanl :: (Add 1 n n1) => (a -> b -> a) -> a -> ListN n b -> ListN n1 a scanl f q (L xs) = L (List.scanl f q xs) --X \index{sscanl@\te{sscanl} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,a_type) --X sscanl( function a_type func(a_type x1, b_type x2), --X a_type q, --X ListN#(vsize,b) vect ); --X \end{libverbatim} sscanl :: (a -> b -> a) -> a -> ListN n b -> ListN n a sscanl f q (L xs) = L (List.sscanl f q xs) --X Combine two ListNs with a function. --X \index{zipWith@\te{zipWith} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,c_type) --X zipWith (function c_type func(a_type x, b_type y), --X ListN#(vsize,a_type) vecta, --X ListN#(vsize,b_type) vectb ); --X \end{libverbatim} zipWith :: (a -> b -> c) -> ListN n a -> ListN n b -> ListN n c zipWith f (L xs) (L ys) = L (List.zipWith f xs ys) --X Combine two ListNs with a function; result is as long as the smaller listN. --X \index{zipWithAny@\te{zipWithAny} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,c_type) --X zipWithAny (function c_type func(a_type x, b_type y), --X ListN#(m,a_type) vecta, --X ListN#(n,b_type) vectb ) --X provisos (Max#(n, vsize, n), Max#(m, vsize, m)); --X \end{libverbatim} zipWithAny :: (Max n mn n, Max m mn m) => (a -> b -> c) -> ListN n a -> ListN m b -> ListN mn c zipWithAny f (L xs) (L ys) = L (List.zipWith f xs ys) --X Combine three ListNs with a function. --X \index{zipWith3@\te{zipWith3} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,d_type) --X zipWith3 ( function d_type func(a_type x, b_type y, c_type z), --X ListN#(vsize,a_type) vecta, --X ListN#(vsize,b_type) vectb, --X ListN#(vsize,c_type) vectc ); --X \end{libverbatim} zipWith3 :: (a -> b -> c -> d) -> ListN n a -> ListN n b -> ListN n c -> ListN n d zipWith3 f (L xs) (L ys) (L zs) = L (List.zipWith3 f xs ys zs) --X Combine three ListNs with a function; result is as long as the smallest listN. --X \index{zipWithAny3@\te{zipWithAny3} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,c_type) --X zipWithAny3 ( function d_type func(a_type x, b_type y, c_type z), --X ListN#(m,a_type) vecta, --X ListN#(n,b_type) vectb, --X ListN#(o,c_type) vectc ) --X provisos (Max#(n, vsize, n), Max#(m, vsize, m), Max#(o, vsize, o)); --X \end{libverbatim} zipWithAny3 :: (Max m mn m, Max n mn n, Max o mn o) => (a -> b -> c -> d) -> ListN n a -> ListN m b -> ListN o c -> ListN mn d zipWithAny3 f (L xs) (L ys) (L zs) = L (List.zipWith3 f xs ys zs) -------------------------------------------------------------------------------- --X \item{\bf ListN to ListN Functions} --X --X --X Move first elements last. --X \index{rotate@\te{rotate} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,a_type) rotate (ListN#(vsize,a_type) vect); --X \end{libverbatim} rotate :: ListN n a -> ListN n a rotate (L xs) = L (List.rotate xs) --X Move last element first. --X \index{rotateR@\te{rotateR} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,a_type) rotateR (ListN#(vsize,a_type) vect); --X \end{libverbatim} rotateR :: ListN n a -> ListN n a rotateR (L xs) = L (List.rotateR xs) --X Reverse element order --X \index{reverse@\te{reverse} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize,a_type) reverse(ListN#(vsize,a_type) vect); --X \end{libverbatim} reverse :: ListN n a -> ListN n a reverse (L xs) = L (List.reverse xs) --X Matrix transposition of a listN of listNs. --X \index{transpose@\te{transpose} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(m,ListN#(n,a_type)) --X transpose ( ListN#(n,ListN#(m,a_type)) matrx ); --X \end{libverbatim} transpose :: ListN m (ListN n a) -> ListN n (ListN m a) transpose (L ls) = L (List.map (\xs -> L xs) (List.transpose (List.map unL ls))) --X Matrix transposition of a ListN of Lists. --X \index{transposeLN@\te{transposeLN} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize, List#(a_type)) --X transposeLN( List#(ListN#(vsize, a_type)) lvs ); --X \end{libverbatim} transposeLN :: List (ListN n a) -> ListN n (List a) transposeLN ls = L (List.transpose (List.map unL ls)) -------------------------------------------------------------------------------- --X --X \item{\bf Monadic Operations} --X --X Within Bluespec, there are some functions which can only be --X invoked in certain contexts. Two common examples are: --X \te{ActionValue}, and module instantiation. ActionValues can only be --X invoked within an \te{Action} context, such as a rule block or an Action --X method, and can be considered as two part -- the action, and the value. --X Module instantiation can similarly be considered, modules can --X only be instantiated in the module context, while the two parts --X are the module instance (the action), and the interface (the --X result). These types are considered monadic. -- XXXX Same something about bind (<-) operation. --X --X When a monadic function is to be applied over a ListN using --X a map-like functions such --X as {\tt map, zipWith}, or {\tt replicate} function, the monadic versions --X of these functions must be used. Moreover, the context requirements of the --X applied function must hold. The common application where for these functions --X are in the generation (or instantiation) of ListNs of hardware --X components. --X --X --X --X {\tt mapM} takes a monadic function and a ListN, and applies the function to --X all ListN elements returning --X the ListN of corresponding results. The second version --X throws away the resulting ListN leaving the action in the its context. --X \index{mapM@\te{mapM} (\te{Monad} function on {\te{ListN}})} --X \begin{libverbatim} --X function m#(ListN#(vsize, b_type)) --X mapM ( function m#(b_type) func(a_type x), --X ListN#(vsize, a_type) vecta ) --X provisos (Monad#(m)); --X \end{libverbatim} mapM :: (Monad m) => (a -> m b) -> ListN n a -> m (ListN n b) mapM f (L xs) = do _ys :: List b {-# hide #-} _ys <- List.mapM f xs return (L _ys) --X --X@ Like {\te{mapM}} but throws away the resulting listN. --X \index{mapM\US@\te{mapM\US} (\te{ListN} function)} --X --X \begin{libverbatim} --X function m#(void) mapM_(function m#(b_type) func(a_type x), --X ListN#(vsize, a_type) vect) --X provisos (Monad#(m)); --X \end{libverbatim} mapM_ :: (Monad m) => (a -> m b) -> ListN n a -> m () mapM_ f xs = do _ <- mapM f xs return () --X@ Combine two listNs with a function. --X \index{zipWithM@\te{zipWithM} (\te{ListN} function)} --X Take a monadic function (which takes two arguments) and two ListNs; --X The function applied to the corresponding element from --X each listN would return an action and result. --X Return an action representing all those actions --X and the listN of corresponding results. The second version --X throws away the result leaving the action. --X --X \begin{libverbatim} --X function m#(ListN#(vsize, c_type)) --X zipWithM( function m#(c_type) func(a_type x, b_type y), --X ListN#(vsize, a_type) vecta, --X ListN#(vsize, b_type) vectb ) --X provisos (Monad#(m)); --X \end{libverbatim} zipWithM :: (Monad m) => (a -> b -> m c) -> ListN n a -> ListN n b -> m (ListN n c) zipWithM f (L xs) (L ys) = do {-# hide #-} _zs <- List.zipWithM f xs ys return (L _zs) --X@ Like {\te{zipWithM}} but throws away the resulting listN --X \index{zipWithM\US@\te{zipWithM\US} (\te{ListN} function)} --X --X \begin{libverbatim} --X function m#(void) --X zipWithM_(function m#(c_type) func(a_type x, b_type y), --X ListN#(vsize, a_type) vecta, --X ListN#(vsize, b_type) vectb ) --X provisos (Monad#(m)); --X \end{libverbatim} zipWithM_ :: (Monad m) => (a -> b -> m c) -> ListN n a -> ListN n b -> m () zipWithM_ f xs ys = do _ <- zipWithM f xs ys return () --X Combine three listNs with a function. --X \index{zipWithM@\te{zipWithM} (\te{ListN} function)} --X Take a function (which takes three arguments) and three ListNs; --X The function applied to the corresponding element from --X each listN would return an action and result. --X Return an action representing all those actions --X and the listN of corresponding results. --X --X \begin{libverbatim} --X function m#(ListN#(vsize, c_type)) --X zipWith3M( function m#(d_type) func(a_type x, b_type y, c_type z), --X ListN#(vsize, a_type) vecta, --X ListN#(vsize, b_type) vectb, --X ListN#(vsize, c_type) vectc ) --X provisos (Monad#(m)); --X \end{libverbatim} zipWith3M :: (Monad m) => (a -> b -> c -> m d) -> ListN n a -> ListN n b -> ListN n c -> m (ListN n d) zipWith3M f (L xs) (L ys) (L zs) = do {-# hide #-} _ws <- List.zipWith3M f xs ys zs return (L _ws) --X Generate a ListN of elements generated by applying the --X given monadic function to 0 through N-1. --X \index{genWithM@\te{genWithM} (\te{ListN} function)} --X \begin{libverbatim} --X function m#(ListN#(vsize, a_type)) genWithM(function m#(a_type) func(Integer x)) --X provisos (Monad#(m)); --X \end{libverbatim} genWithM :: (Monad m) => (Integer -> m a) -> m (ListN n a) genWithM f = mapM f genList --X Generate a ListN of elements generated by using --X the given monadic value repeatedly. --X \index{replicateM@\te{replicateM} (\te{ListN} function)} --X \begin{libverbatim} --X function m#(ListN#(vsize, a_type)) replicateM( m#(a_type) c) --X provisos (Monad#(m)); --X \end{libverbatim} replicateM :: (Monad m) => m a -> m (ListN n a) replicateM c = mapM (const c) genList --X \index{foldlM@\te{foldlM} (\te{ListN} function)} --X \begin{libverbatim} --X function m#(b_type) foldlM ( --X function m#(b_type) func(b_type y, a_type x), --X b_type initb, --X ListN#(vsize,a_type) vect ) --X provisos (Monad#(m)); --X \end{libverbatim} foldlM :: (Monad m) => (a -> b -> m a) -> a -> ListN n b -> m a foldlM f a (L xs) = List.foldlM f a xs --X \index{foldM@\te{foldM} (\te{ListN} function)} --X \begin{libverbatim} --X function m#(a_type) foldM ( --X function m#(a_type) func(a_type y, a_type x), --X ListN#(vsize,a_type) vecta ) --X provisos (Monad#(m), Add#(1, xxx, vsize)); // ListN has at least 1 element --X \end{libverbatim} foldM :: (Monad m, Add 1 k n) => (a -> a -> m a) -> ListN n a -> m a foldM f (L xs) = List.foldM f xs --X --X \index{foldM@\te{foldM} (\te{ListN} function)} --X \begin{libverbatim} --X function m#(b_type) foldrM ( --X function m#(b_type) func(a_type x, b_type y), --X b_type e, --X ListN#(vsize,a_type) vecta ) --X provisos (Monad#(m)); --X \end{libverbatim} foldrM :: (Monad m) => (a -> b -> m b) -> b -> ListN n a -> m b foldrM f a (L xs) = List.foldrM f a xs --X@ Take a ListN of actions; return an action representing --X@ performing all those actions and returning the ListN --X@ of all the results. --X@ \index{sequence@\te{sequence} (\te{Monad} function on {\te{ListN})}} --X@ \begin{libverbatim} --X@ function m#(ListN#(vsize, a_type)) sequence (ListN#(vsize, m#(a_type))) --X@ provisos (Monad#(m)); --X@ \end{libverbatim} sequence :: (Monad m) => ListN n (m a) -> m (ListN n a) sequence (L xs) = do ys :: List a ys <- List.sequence xs return (L ys) ---------------------------------------------------------------------------- --X \item{\bf Tests on ListNs} --X --X Check if an element is in a listN. --X \index{elem@\te{elem} (\te{ListN} function)} --X \begin{libverbatim} --X function Bool elem (a_type x, ListN#(vsize,a_type) vect ) --X provisos (Eq#(a_type)); --X \end{libverbatim} elem :: (Eq a) => a -> ListN n a -> Bool elem y (L xs) = List.elem y xs --X Test if a predicate holds for any or all elements of a listN. --X \index{all@\te{all} (\te{ListN} function)} --X \index{any@\te{any} (\te{ListN} function)} --X \begin{libverbatim} --X function Bool any(function Bool pred(a_type x1), --X ListN#(vsize,a_type) vect ); --X \end{libverbatim} any :: (a -> Bool) -> ListN n a -> Bool any p (L xs) = List.any p xs --X \begin{libverbatim} --X function Bool all(function Bool pred(a_type x1), --X ListN#(vsize,a_type) vect ); --X \end{libverbatim} all :: (a -> Bool) -> ListN n a -> Bool all p (L xs) = List.all p xs ------------------------------------------------------------------------------------- --X \item{\bf Converting to and from ListNs} --X --X There are functions which convert to and from a \te{List} and a \te{ListN}. --X \index{toList@\te{toList} (\te{ListN} function)} --X \begin{libverbatim} --X function List#(a_type) toList (ListN#(vsize, a_type) vect); --X \end{libverbatim} toList :: ListN n a -> List a toList (L xs) = xs --X@ Convert an ordinary list to a ListN. --X \index{toListN@\te{toListN} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize, a_type) toListN ( List#(a_type) lst); --X \end{libverbatim} toListN :: List a -> ListN n a toListN xs = if length xs /= valueOf n then error ("ListN.toListN: bad argument length " +++ integerToString (length xs) +++ " /= " +++ integerToString (valueOf n)) else L xs --------------------------------------------------------------------------------------------------- --X \item{\bf Miscellaneous Functions on ListNs} --X --X Join a number of actions together. --X \index{joinActions@\te{joinActions} (\te{ListN} function)} --X \begin{libverbatim} --X function Action joinActions (ListN#(vsize,Action) vactions); --X \end{libverbatim} joinActions :: ListN n Action -> Action joinActions (L as) = List.joinActions as --X Join a number of rules together. --X \index{joinRules@\te{joinRules} (\te{ListN} function)} --X \begin{libverbatim} --X function Rules joinRules (ListN#(vsize,Rules) vrules); --X \end{libverbatim} joinRules :: ListN n Rules -> Rules joinRules (L rs) = List.joinRules rs --X Map a function, but pass an accumulator from head to tail. --X \index{mapAccumL@\te{mapAccumL} (\te{ListN} function)} --X \begin{libverbatim} --X function Tuple2 #(a_type, ListN#(vsize,c_type)) --X mapAccumL ( function Tuple2 #(a_type, c_type) func(a_type x, b_type y), --X a_type x0, --X ListN#(vsize,b_type) vect ); --X \end{libverbatim} mapAccumL :: (a -> b -> (a, c)) -> a -> ListN n b -> (a, ListN n c) mapAccumL f s (L xs) = letseq (s', ys) = List.mapAccumL f s xs in (s', L ys) --X Map a function, but pass an accumulator from tail to head. --X \index{mapAccumR@\te{mapAccumR} (\te{ListN} function)} --X \begin{libverbatim} --X function Tuple2 #(a_type, ListN#(vsize,c_type)) --X mapAccumR( function Tuple2 #(a_type, c_type) func(a_type x, b_type y), --X a_type x0, --X ListN#(vsize,b_type) vect ); --X \end{libverbatim} mapAccumR :: (a -> b -> (a, c)) -> a -> ListN n b -> (a, ListN n c) mapAccumR f s (L xs) = letseq (s', ys) = List.mapAccumR f s xs in (s', L ys) --X Map a function over a listN consuming two elements at a time. --X Any straggling element is processed by the second function. --X \index{mapPairs@\te{mapPairs} (\te{ListN} function)} --X \begin{libverbatim} --X function ListN#(vsize2,b_type) --X mapPairs ( --X function b_type func1(a_type x, a_type y), --X function b_type func2(a_type x), --X ListN#(vsize,a_type) vect ) --X provisos (Div#(vsize, 2, vsize2)); --X \end{libverbatim} mapPairs :: (Div n 2 n2) => (a -> a -> b) -> (a -> b) -> ListN n a -> ListN n2 b mapPairs f g (L xs) = L (List.mapPairs f g xs) --X \item{\bf Examples Using the ListN Type} --X --X The following example shows some common uses of the {\te{ListN}} --X type. We first create a ListN of registers, and show how to --X populate this listN. We then continue with some examples of --X accessing and updating the registers within the ListN, as --X well as alternate ways to do the same. --X --X --X \begin{libverbatim} --X // First define a variable to hold the registers. --X // Notice the variable is really a ListN of Interfaces of type Reg, --X // not a listN of modules. --X ListN#(10,Reg#(DataT)) vectRegs ; --X --X // Now we want to populate the ListN, by filling it with Reg type --X // interfaces, via the mkReg module. --X // Notice that the replicateM function is used since mkReg function --X // is creating a module. --X vectRegs <- replicateM( mkReg( 0 ) ) ; --X --X // ... --X --X // A rule showing a read and write of one register within the --X // ListN. --X // The readReg function is required since the selection of an --X // element from vectRegs returns a Reg#(DType) interface, not the --X // value of the register. The readReg functions converts from a --X // Reg#(DataT) type to a DataT type. --X rule zerothElement ( readReg( vectRegs[0] ) > 20 ) ; --X // set 0 element to 0 --X // The parentheses are required in this context to give --X // precedence to the selection over the write operation. --X (vectRegs[0]) <= 0 ; --X --X // Set the 1st element to 5 --X // An alternate syntax --X vectRegs[1]._write( 5 ) ; --X endrule --X --X rule lastElement ( readReg( vectRegs[9] ) > 200 ) ; --X // Set the 9th element to -10000 --X (vectRegs[9]) <= -10000 ; --X endrule --X --X // These rules defined above can execute simultaneously, since --X // they touch independent registers --X --X // Here is an example of dynamic selection, first we define a --X // register to be used as the selector. --X Reg#(UInt#(4)) selector <- mkReg(0) ; --X --X // Now define another Reg variable which is selected from the --X // vectReg variable. Note that no register is created here, just --X // an alias is defined. --X Reg#(DataT) thisReg = select(vectRegs, selector ) ; --X --X // If the selected register is greater than 20'h7_0000, then its --X // value is reset to zero. Note that the ListN update function in --X // not required since we are changing the contents of a register --X // not the ListN vectReg. --X rule reduceReg( thisReg > 20'h7_0000 ) ; --X thisReg <= 0 ; --X selector <= ( selector < 9 ) ? selector + 1 : 0 ; --X endrule --X --X // As an alternative, we can define create n rules which check the --X // value of each register and update accordingly. This is done by --X // generating each rule inside an elaboration-time for-loop. --X // The --X Integer i; // a compile time variable --X for ( i = 0 ; i < 10 ; i = i + 1 ) begin --X rule checkValue( readReg( vectRegs[i] ) > 20'h7_0000 ) ; --X (vectRegs[i]) <= 0 ; --X endrule --X end --X \end{libverbatim} --X \end{itemize} -- The generic representation of a ListN is a vector of generic representations instance Generic (ListN n a) (Meta (MetaData "ListN" "ListN" (NumArg n, StarArg a) 1) (Vector n (Conc a))) where from l = Meta $ (Vector.map Conc) $ toVector $ toList l to (Meta v) = toListN $ Vector.toList $ Vector.map (\ Conc x -> x) v