Skip to content

Commit

Permalink
#39 Fix fromListWithDef divergence
Browse files Browse the repository at this point in the history
fromListWithDef diverges when passed an infinite list, for the following
reasons:

Reason 1:

  * fromListWithDef calls Data.Primitive.Array.fromListN (bits + 1).
    fromListN requires that the length of the list that is passed to it
    is exactly bits + 1. To ensure this, it forces the spine of the list
    that is passed to it.

  * The list that is passed to fromListN is generated by go0, which
    calls go. When xs is infinite, go k xs will be infinite. Therefore,
    fromListN will throw an error since go0 yields a list longer than
    bits + 1.

Even if we take the first bits + 1 elements of go0 before passing to
fromListN, there is another problem.

Reason 2:

  * As fromListN forces the spine, it will compute go 0 xs0, go 1 xs1,
    ..., go 63 xs63, for some xs0, xs1, ..., xs63.

  * This in turn requires computing measureOff (2^0) xs0,
    measureOff (2^1) x1, ..., measureOff (2^63) x63, which is
    essentially divergent.

To avoid these problems, we implement fromListWithDef in terms of
fromInfinite. Note that the implementation of fromInfinite is similar to
the old implementation of fromListWithDef, except that it doesn't call
measureOff, which is the source of the divergence.
  • Loading branch information
pgujjula committed Apr 12, 2024
1 parent 3e5729e commit e6f97b6
Showing 1 changed file with 1 addition and 26 deletions.
27 changes: 1 addition & 26 deletions src/Data/Chimera/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}
Expand Down Expand Up @@ -518,17 +516,6 @@ toInfinite = foldr (:<)
foldr :: G.Vector v a => (a -> b -> b) -> Chimera v a -> b
foldr f (Chimera vs) = F.foldr (flip $ G.foldr f) undefined vs

measureOff :: Int -> [a] -> Either Int ([a], [a])
measureOff n
| n <= 0 = Right . ([],)
| otherwise = go n
where
go m [] = Left m
go 1 (x : xs) = Right ([x], xs)
go m (x : xs) = case go (m - 1) xs of
l@Left {} -> l
Right (xs', xs'') -> Right (x : xs', xs'')

measureOffVector :: G.Vector v a => Int -> v a -> Either Int (v a, v a)
measureOffVector n xs
| n <= l = Right (G.splitAt n xs)
Expand All @@ -547,19 +534,7 @@ fromListWithDef
-> [a]
-- ^ Prefix
-> Chimera v a
fromListWithDef a = Chimera . fromListN (bits + 1) . go0
where
go0 = \case
[] -> G.singleton a : map (\k -> G.replicate (1 `shiftL` k) a) [0 .. bits - 1]
x : xs -> G.singleton x : go 0 xs

go k xs = case measureOff kk xs of
Left l ->
G.fromListN kk (xs ++ replicate l a)
: map (\n -> G.replicate (1 `shiftL` n) a) [k + 1 .. bits - 1]
Right (ys, zs) -> G.fromListN kk ys : go (k + 1) zs
where
kk = 1 `shiftL` k
fromListWithDef a as = fromInfinite (Inf.prependList as (Inf.repeat a))

-- | Create a stream of values from a given infinite list.
--
Expand Down

0 comments on commit e6f97b6

Please sign in to comment.