PageRenderTime 24ms CodeModel.GetById 1ms app.highlight 6ms RepoModel.GetById 15ms app.codeStats 0ms

/stream.coffee

http://github.com/MichaelBlume/coffeestream
CoffeeScript | 153 lines | 147 code | 5 blank | 1 comment | 29 complexity | 4b23158117f8c4addac903ee6fdddc81 MD5 | raw file
  1plus = (a,b) -> a+b
  2eq = (a,b) -> a==b
  3mirror = (x) -> x
  4nonce=[]
  5class Stream
  6    constructor: (@_head=nonce, @_tail) ->
  7        if not @empty() and not @_tail?
  8            @_tail = new Stream()
  9
 10    @make: (head=nonce, rest...) ->
 11        if head != nonce
 12            new Stream head, -> Stream.make rest...
 13        else
 14            new Stream()
 15    @repeat: (x) ->
 16        s=new Stream x, -> s
 17    @recursive: (f, inits...) ->
 18        n = inits.length
 19        helper = (index) ->
 20            if n > index
 21                new Stream inits[index], -> helper index+1
 22            else
 23                midstreamhelper result
 24        midstreamhelper = (s) ->
 25            next = f(s.take(n).list()...)
 26            new Stream next, -> midstreamhelper s.tail()
 27        result = new Stream inits[0], -> helper 1
 28    @range: (min=1, max='never') ->
 29        if min == max
 30            Stream.make(min)
 31        else new Stream min, -> Stream.range(min+1, max)
 32
 33    empty: -> @_head == nonce
 34    throw_if_empty: ->
 35        if @empty()
 36            throw error: "end of stream"
 37    head: ->
 38        @throw_if_empty()
 39        @_head
 40    tail: ->
 41        @throw_if_empty()
 42        if @_tail not instanceof Stream
 43            @_tail = @_tail()
 44        @_tail
 45    item: (n) -> @skip(n).head()
 46    skip: (n) ->
 47        s = this
 48        while n != 0
 49            n--
 50            s = s.tail()
 51        s
 52    walk: (f) ->
 53        s = this
 54        until s.empty()
 55            f s.head()
 56            s = s.tail()
 57        null
 58    print: -> @walk console.log
 59    force: -> @walk ->
 60    map: (f) ->
 61        if @empty()
 62            new Stream()
 63        else
 64            new Stream f(@head()), => @tail().map f
 65    filter: (f) ->
 66        s = this
 67        until s.empty() or f s.head()
 68            s = s.tail()
 69        return new Stream() if s.empty()
 70        new Stream s.head(), -> s.tail().filter f
 71    any: (f=mirror) -> not @filter(f).empty()
 72    all: (f=mirror) ->
 73        negated = (x) -> not f x
 74        not @any(negated)
 75    take: (n) ->
 76        return new Stream() if n==0
 77        new Stream @head(), =>
 78            return new Stream() if n==1
 79            @tail().take n-1
 80    scale: (factor) ->
 81        scaleone = (n) -> factor*n
 82        @map(scaleone)
 83    zip: (zipper, otherstream) ->
 84        mismatch = -> throw error: "length mismatch"
 85        if @empty()
 86            if otherstream.empty()
 87                new Stream()
 88            else
 89                mismatch()
 90        else if otherstream.empty()
 91            mismatch()
 92        else
 93            new Stream zipper(@head(), otherstream.head()), =>
 94                @tail().zip(zipper, otherstream.tail())
 95    append: (s) ->
 96        if @empty()
 97            s
 98        else
 99            new Stream @head(), => @tail().append(s)
100    cycle: ->
101        if @empty()
102            throw error: "zero times infinity"
103        s = new Stream @head(), => @tail().append(s)
104    add: (otherstream) -> @zip plus, otherstream
105    reduce: (reducer, initial) ->
106        @walk (element) -> initial = reducer initial, element
107        initial
108    sum: -> @reduce(plus, 0)
109    length: ->
110        l = 0
111        @walk -> l++
112        l
113    list: ->
114        out = []
115        @walk (n) -> out.push n
116        out
117    until: (f) ->
118        return new Stream() if @empty() or f @head()
119        new Stream @head(), => @tail().until f
120    up_until: (f) ->
121        return new Stream() if @empty()
122        new Stream @head(), =>
123            if f @head()
124                new Stream()
125            else
126                @tail().up_until f
127    equal: (s) ->
128        try
129            bstream = @zip eq, s
130            bstream.all()
131        catch err
132            if err.error != "length mismatch"
133                throw err
134            false
135    member: (x) -> @any (m) -> m==x
136
137output = exports or window
138output.Stream = Stream
139
140primeStream = new Stream 2, ->
141    Stream.range(3).filter (primeCandidate) ->
142        primeStream.until((prime)->
143            prime*prime > primeCandidate
144        ).all (prime)->
145            primeCandidate%prime != 0
146output.primeStream = primeStream
147
148#in general, it is not possible to tell if a stream is finite.
149paradoxicalStream = new Stream 1, ->
150    if paradoxicalStream.is_finite()
151        Stream.repeat(1)
152    else
153        new Stream()