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

  * Add a check in go to break recursion and ensure that the list that
    is passed to fromListN has length (bits + 1).

  * Rearrange how we compute go, so that measureOff is not forced while
    forcing the spine of go.
  • Loading branch information
pgujjula authored and Bodigrim committed Apr 12, 2024
1 parent 3cadb3c commit 14581e6
Showing 1 changed file with 13 additions and 5 deletions.
18 changes: 13 additions & 5 deletions src/Data/Chimera/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -553,13 +553,21 @@ fromListWithDef a = Chimera . fromListN (bits + 1) . go0
[] -> 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
go k xs =
if k == bits
then []
else v : go (k + 1) zs
where
kk = 1 `shiftL` k
(v, zs) =
case measureOff kk xs of
Left l ->
( if l == kk
then G.replicate kk a
else G.fromListN kk (xs ++ replicate l a)
, []
)
Right (ys, zs') -> (G.fromListN kk ys, zs')

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

0 comments on commit 14581e6

Please sign in to comment.