top | item 11516606

(no title)

luismarques | 10 years ago

If you want to check how this idea is taken to way more sophisticated levels than this, then check out D's ranges and algorithms. This article only covers the equivalent of input iterators / ranges. You can also find in D sophisticated ways to deal with the last part of the article, regarding how to ascertain the different capabilities of your range/type, in ways that go beyond the traditional type system and OOP concepts.

edit: (also, D's lazy keyword, which performs the transformation described in the article automatically)

discuss

order

jewbacca|10 years ago

It also wouldn't be a complete discussion of the subject without at least mentioning Haskell, in which everything is lazy by default:

    numbers = [0,1,2,3,4,5,6,7,8,9]
    take 5 numbers
    -- [0,1,2,3,4]

    numbers = [0..]
    take 5 numbers
    -- [0,1,2,3,4]

    evenNumbers = map (* 2) numbers
    take 5 evenNumbers
    -- [0,2,4,6,8]

    last evenNumbers
    -- <<infinite loop>>
I used simple list stuff in this illustration, but everything is lazy. I/O most notably (and sometimes problematically). Nothing runs until it's forced[0], and none of this requires any special annotation or plumbing.

----

[0] Yes, I know. But it's subtle, and we're in public here. https://wiki.haskell.org/Lazy_vs._non-strict

JoshTriplett|10 years ago

Haskell's laziness can also be a notorious source of "space leaks": an algorithm that appears O(1) in space, such as summing up a list of numbers, can actually use O(n) space by accumulating unevaluated invocations of (+) in memory. With more complex data structures, the proportion of expected memory usage to actual memory usage can get even worse.

In larger Haskell programs, I've found that the most challenging issue to debug: "why does my program use way too much memory?".