Skip to content

Instantly share code, notes, and snippets.

@rsms

rsms/lazyseq.ts Secret

Created October 3, 2019 02:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rsms/31017d5360030044659adb95a5488283 to your computer and use it in GitHub Desktop.
Save rsms/31017d5360030044659adb95a5488283 to your computer and use it in GitHub Desktop.
export interface LazySeq<T, OffsT = T|undefined, LenT = number|undefined> extends Iterable<T> {
// duplicated in scripter-env.d.ts
readonly length :LenT // Infinity if unbounded
map<R>(f :(value :T, index :number)=>R) :R[]
array() :T[]
at(index :number) :OffsT
join(glue :string) :string
}
export class LazyNumberSequence implements LazySeq<number,number,number> {
readonly __scripter_lazy_seq__ = "n"
readonly length :number
readonly start :number
readonly end :number
readonly step :number
constructor(start :number, end :number, step :number) {
this.length = end === Infinity ? Infinity : Math.ceil(Math.max(0, end - start) / step)
this.start = start
this.end = end
this.step = step
}
[Symbol.iterator]() :Iterator<number> {
let value = this.start, end = this.end, step = this.step
return {
next() :IteratorResult<number> {
if (value >= end) {
return {done:true, value:0}
}
let v = value
value += step
return {value: v, done:false}
}
}
}
map<R>(f :(value :number, index :number)=>R) :R[] {
if (this.end === Infinity) {
throw new Error("infinite sequence")
}
let a :R[] = []
for (let i = 0, v = this.start; v < this.end; v += this.step) {
a.push(f(v, i++))
}
return a
}
array() :number[] {
if (this.end === Infinity) {
throw new Error("infinite sequence")
}
let a :number[] = []
for (let v = this.start; v < this.end; v += this.step) {
a.push(v)
}
return a
}
toString() :string {
let glue = ", "
if (this.end === Infinity) {
let s = ""
let i = 0
for (let val of this) {
if (i > 0) {
if (i > 50) {
s += " ... ∞"
break
}
s += glue
}
s += val
i++
}
return s
}
return this.join(glue)
}
join(glue :string) :string {
let s = ""
let i = 0
if (this.end === Infinity) {
throw new Error("infinite sequence")
} else {
for (let val of this) {
if (i > 0) {
s += glue
}
s += val
i++
}
}
return s
}
at(index :number) :number {
return this.start + (this.step * index)
}
}
// range(start :number, end :number, step? :number) :LazySequence<number>
// range(end :number) :LazySequence<number>
env.range = function range(start, end, step) {
if (end === undefined) {
end = start
start = 0
step = 1
} else if (step === undefined || step < 1) {
step = 1
}
return new scriptLib.LazyNumberSequence(start, end, step)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment