[Haskell-cafe] Improving *> and >> for Data.Sequence

Ross Paterson R.Paterson at city.ac.uk
Sat Nov 22 10:49:18 UTC 2014


On Fri, Nov 21, 2014 at 02:00:16PM -0500, David Feuer wrote:
> To be precise, I *think* using the fromList approach for <*> makes us create O
> (n) thunks in order to extract the last element of the result. If we build the
> result inward, I *think* we can avoid this, getting the last element of the
> result in O(1) time and space. But my understanding of this data structure
> remains primitive.

This modification of the previous should do that.

mult :: Seq (a -> b) -> Seq a -> Seq b
mult sfs sxs = fromTwoLists (length sfs * length sxs) ys rev_ys
  where
    fs = toList sfs
    rev_fs = toRevList sfs
    xs = toList sxs
    rev_xs = toRevList sxs
    ys = [f x | f <- fs, x <- xs]
    rev_ys = [f x | f <- rev_fs, x <- rev_xs]

-- toRevList xs = toList (reverse xs)
toRevList :: Seq a -> [a]
toRevList = foldl (flip (:)) []

-- Build a tree lazy in the middle, from a list and its reverse.
--
-- fromTwoLists (length xs) xs (reverse xs) = fromList xs
--
-- Getting the kth element from either end involves forcing the lists
-- to length k.
fromTwoLists :: Int -> [a] -> [a] -> Seq a
fromTwoLists len_xs xs rev_xs =
    Seq $ mkTree2 len_xs 1 (map Elem xs) (map Elem rev_xs)

-- Construct a fingertree from the first n elements of xs.
-- The arguments must satisfy n <= length xs && rev_xs = reverse xs.
-- Each element of xs has the same size, provided as an argument.
mkTree2 :: Int -> Int -> [a] -> [a] -> FingerTree a
mkTree2 n size xs rev_xs
  | n == 0 = Empty
  | n == 1 = let [x1] = xs in Single x1
  | n <  6 = let
            nl = n `div` 2
            l = Data.List.take nl xs
            r = Data.List.take (n - nl) rev_xs
        in Deep totalSize (mkDigit l) Empty (mkRevDigit r)
  | otherwise = let
            size' = 3*size
            n' = (n-4) `div` 3
            digits = n - n'*3
            nl = digits `div` 2
            (l, xs') = Data.List.splitAt nl xs
            (r, rev_xs') = Data.List.splitAt (digits - nl) rev_xs
            nodes = mkNodes size' xs'
            rev_nodes = mkRevNodes size' rev_xs'
        in Deep totalSize (mkDigit l) (mkTree2 n' size' nodes rev_nodes) (mkRevDigit r)
  where
    totalSize = n*size

mkDigit :: [a] -> Digit a
mkDigit [x1] = One x1
mkDigit [x1, x2] = Two x1 x2
mkDigit [x1, x2, x3] = Three x1 x2 x3
mkDigit [x1, x2, x3, x4] = Four x1 x2 x3 x4

-- length xs <= 4 => mkRevDigit xs = mkDigit (reverse xs)
mkRevDigit :: [a] -> Digit a
mkRevDigit [x1] = One x1
mkRevDigit [x2, x1] = Two x1 x2
mkRevDigit [x3, x2, x1] = Three x1 x2 x3
mkRevDigit [x4, x3, x2, x1] = Four x1 x2 x3 x4

mkNodes :: Int -> [a] -> [Node a]
mkNodes size (x1:x2:x3:xs) = Node3 size x1 x2 x3:mkNodes size xs

-- length xs `mod` 3 == 0 =>
--    mkRevNodes size xs = reverse (mkNodes size (reverse xs))
mkRevNodes :: Int -> [a] -> [Node a]
mkRevNodes size (x3:x2:x1:xs) = Node3 size x1 x2 x3:mkRevNodes size xs


More information about the Haskell-Cafe mailing list