Ryan Ingram wrote:
On 10/24/07, apfelmus <[EMAIL PROTECTED]> wrote:
So, instead of storing a list [∃a. Show a => a], you may as well store a
list of strings [String].

I've seen this before, and to some extent I agree with it, but it
breaks down for bigger examples due to sharing.

In most cases, "x" has a more compact representation than the result
of evaluating "show x".  So if you keep a list of [show x, show y,
show z] around for a long period of time, you're leaking space.
Consider instead:

data StringFn where
   StringFn :: forall a. a -> (a -> String) -> StringFn

applyStringFn :: StringFn -> String
applyStringFn (StringFn a f) = f a

[ StringFn x show, StringFn y show, StringFn z show ]

Now, you use more time every time you compute the result, but StringFn
has a compact representation; you're not leaking the space used for
the string throughout the execution of the program, but only
allocating it while it's used.

Indeed. (Although the effect will be marginal in this particular example since the unevaluated thunk (show x) is represented as compactly as x . But the time-space trade-off would matter when strings from the list are used several times.)

In a sense, that's also the reason why stream fusion à la Duncan + Roman + Don uses an existential type

  data Stream a where
    Stream :: ∀s. s -> (s -> Step a s) -> Stream a

  data Step a s = Done
                | Yield a s
                | Skip s

I mean, every stream can be represented by the list of its results but the observation for fusion is that there is a much more compact representation for the state (like an integer for [1..] or the source list in map f . map g $ [x,y,...])

Regards,
apfelmus

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to