6.63. kink/iter/IFUN¶
Operations of ifuns.
“ifun” is an abbreviation of “iterator function.” An ifun is a fun which works as a pointer of a finite-length or infinite-length stream of values.
Usually, it is more convenient to use iters, which are wrappers of ifuns, rather than directly using ifuns. See kink/iter/ITER for iters.
Specification
An ifun is a 2ary fun, which takes $proc and $fin as arguments. The ifun must tail-call $proc if it has an element, or $fin if it has no element.
$proc is a 2ary fun, which takes `Head` and $tail as arguments. The ifun passes its first element as `Head`, and passes the next ifun, which points to remaining elements after `Head`, as $tail.
$fin is a thunk, which is tail-called when the ifun has no element.
Examples
In the next program, `make_vec_ifun` makes an ifun which iterates over the elements of `Vec`.
:make_vec_ifun <- {(:Vec)
{(:proc :fin)
if(Vec.any?
{ :Head = Vec.get(0)
:tail = make_vec_ifun(Vec.drop_front(1))
proc(Head $tail)
}
{ fin }
)
}
}
Let's make an `ifun`.
:nums_ifun <- make_vec_ifun([100 200 300])
You can iterate over the elements of $nums_ifun using IFUN.each.
:IFUN.require_from('kink/iter/')
IFUN.each(
$nums_ifun
{(:N) stdout.print_line(N.repr) }
)
# Output:
# 100
# 200
# 300
You can make another ifun mapping the elements.
:doubled_ifun <- IFUN.map($nums_ifun {(:N) N * 2 })
IFUN.each(
$doubled_ifun
{(:N) stdout.print_line(N.repr) }
)
# Output:
# 200
# 400
# 600
You can accumulate the elements.
:Sum <- IFUN.fold($nums_ifun 0 {(:X :Y) X + Y })
stdout.print_line(Sum.repr) # => 600
6.63.1. IFUN.each($ifun $consume)¶
`each` calls $consume with each element of $ifun, then returns the last result of $consume.
If $ifun has no elements, `each` returns nada.
Preconditions
$ifun must be an ifun.
$consume must be a fun which takes an arg.
Example
:IFUN.require_from('kink/iter/')
IFUN.each(IFUN.of(1 2 3)){(:E)
stdout.print_line(E.repr)
}
# Output:
# 1
# 2
# 3
6.63.2. IFUN.map($ifun $transform)¶
`map` returns an ifun whose nth element is transform(nth-element-of-$ifun).
Preconditions
$ifun must be an ifun.
$transform must take an arg.
Example
:IFUN.require_from('kink/iter/')
:Ns <- IFUN.of(1 2 3 4)
:Doubles <- IFUN.map(Ns){(:N) N * 2 }
IFUN.each(Doubles){(:D)
stdout.print_line(D.repr)
}
# Output:
# 2
# 4
# 6
# 8
6.63.3. IFUN.concat_map($ifun $to_ifun)¶
`concat_map` returns an ifun which contains elements of ifuns which are results of to_ifun(element-of-$ifun).
Preconditions
$ifun must be an ifun.
$to_ifun must take an arg, and returns an ifun.
Example
:IFUN.require_from('kink/iter/')
:Ns <- IFUN.of(1 2 3 4)
:Mapped <- IFUN.concat_map(Ns){(:N)
N.times.ifun
}
IFUN.each(Mapped){(:M) stdout.print_line(M.repr) }
# => 0 0 1 0 1 2 0 1 2 3
6.63.4. IFUN.filter($ifun $include?)¶
`filter` returns all the elements of $ifun which satisfy $include?, as an ifun. The order of elements is not changed.
Preconditions
$ifun must be an ifun.
$include? must be a predicate.
Example
:IFUN.require_from('kink/iter/')
:Orig <- IFUN.of(1 2 3 4 5 6 7 8 9)
:Evens <- IFUN.filter(Orig){(:N) N % 2 == 0 }
IFUN.each(Evens){(:N)
stdout.print_line(N.repr)
}
# Output:
# 2
# 4
# 6
# 8
6.63.5. IFUN.count($ifun $counted?)¶
`count` returns the number of elements of $ifun, which satisfy $counted?.
The result is an int `num`.
Preconditions
$ifun must be an ifun.
$counted? must be a predicate.
Example
:IFUN.require_from('kink/iter/')
:ifun <- IFUN.of(1 2 3 4 5 6 7 8 9)
:Count <- IFUN.count($ifun){(:N) N % 2 == 0 }
stdout.print_line(Count.repr) # => 4
6.63.6. IFUN.fold($ifun Init $combine)¶
`fold` folds elements of $ifun seeded by `Init`.
If the elements of $ifun is E1, E2, ,,, En_1, En, `fold` returns combine(combine(,,,combine(combine(Init E1) E2),,, En_1) En).
If $ifun is empty, `fold` returns `Init`.
Preconditions
$ifun must be an ifun.
$combine must take two args.
Example
:IFUN.require_from('kink/iter/')
:Ns <- IFUN.of(1 2 3 4 5)
stdout.print_line(IFUN.fold(Ns 100){(:X :Y) X + Y }.repr) # => 115
6.63.7. IFUN.reduce($ifun $combine ...[$empty_fallback])¶
`reduce` folds elements of $ifun mutually.
If $ifun has elements E1, E2, E3, ,,, En_1, En, `reduce` returns combine(combine(,,,combine(combine(E1 E2) E3),,, En_1) En).
If $ifun has a single element `E`, `reduce` returns `E`.
If $ifun has no element, and $empty_fallback is given, `reduce` tail-calls $empty_fallback with no arg.
If $ifun has no element, and $empty_fallback is not given, `reduce` raises an exception.
Preconditions
$ifun must be an ifun.
$combine must take two args.
$empty_fallback must be a thunk.
Example
:IFUN.require_from('kink/iter/')
:Ns <- IFUN.of(1 2 3 4 5)
stdout.print_line(IFUN.reduce(Ns){(:X :Y) X + Y }.repr) # => 15
6.63.8. IFUN.take_front($ifun N)¶
`take_front` returns an ifun containing the first N elements of $ifun, or all the elements if $ifun has less than N elements.
Preconditions
$ifun must be an ifun.
`N` must be an int `num`.
Example
:IFUN.require_from('kink/iter/')
IFUN.each(IFUN.take_front(1.up.ifun 5)){(:N)
stdout.print_line(N.repr)
}
# => 1 2 3 4 5
IFUN.each(IFUN.take_front(IFUN.of(1 2 3) 5)){(:N)
stdout.print_line(N.repr)
}
# => 1 2 3
6.63.9. IFUN.drop_front($ifun N)¶
`drop_front` returns an ifun omitting the first N elements of $ifun, or an empty ifun if $ifun has less than N elements.
Preconditions
$ifun must be an ifun.
`N` must be an int `num`.
Example
:IFUN.require_from('kink/iter/')
IFUN.each(IFUN.drop_front(10.times.ifun 5)){(:N)
stdout.print_line(N.repr)
}
# => 5 6 7 8 9
IFUN.each(IFUN.drop_front(10.times.ifun 20)){(:N)
stdout.print_line(N.repr)
}
# Output: nothing
6.63.10. IFUN.take_while($ifun $include?)¶
`take_while` returns an ifun of the longest initial prefix of $ifun, whose elements all satisfy $include?.
Preconditions
$ifun must be an ifun.
$include? must be a predicate.
Example
:IFUN.require_from('kink/iter/')
:ns <- IFUN.of(1000 500 250 125 62 31 15 7 3 1 0)
:front <- IFUN.take_while($ns){(:N) N % 2 == 0 }
IFUN.each($front){(:N) stdout.print_line(N.repr) }
# => 1000 500 250
6.63.11. IFUN.drop_while($ifun $exclude?)¶
`drop_while` returns an ifun after the longest initial prefix of $ifun, whose elements all satisfy $exclude?.
Preconditions
$ifun must be an ifun.
$exclude? must be a predicate.
Example
:IFUN.require_from('kink/iter/')
:ns <- IFUN.of(1000 500 250 125 62 31 15 7 3 1 0)
:back <- IFUN.drop_while($ns){(:N) N % 2 == 0 }
IFUN.each($back){(:N) stdout.print_line(N.repr) }
# => 125 62 31 15 7 3 1 0
6.63.12. IFUN.all?($ifun $match?)¶
`all?` returns true if all the elements of $ifun satisfy $match?, otherwise returns false.
If $ifun is infinite-length, `all?` is not guaranteed to return.
Preconditions
$ifun must be an ifun.
$match? must be a predicate.
Example
:IFUN.require_from('kink/iter/')
:ns <- IFUN.of(1 2 3 4 5)
stdout.print_line(IFUN.all?($ns){(:N) N < 10 }.repr) # => true
stdout.print_line(IFUN.all?($ns){(:N) N % 2 == 0 }.repr) # => false
6.63.13. IFUN.any?($ifun $match?)¶
`any?` returns true if one or more elements of $ifun satisfy $match?, otherwise returns false.
If $ifun is infinite-length, `any?` is not guaranteed to return.
Preconditions
$ifun must be an ifun.
$match? must be a predicate.
Example
:IFUN.require_from('kink/iter/')
:ns <- IFUN.of(1 2 3 4 5)
stdout.print_line(IFUN.any?($ns){(:N) N % 2 == 0 }.repr) # => true
stdout.print_line(IFUN.any?($ns){(:N) N > 10 }.repr) # => false
6.63.14. IFUN.concat($ifun_of_ifuns)¶
`concat` returns an ifun which concatenates the ifuns contained in $ifun_of_ifuns.
Preconditions
$ifun_of_ifuns must be an ifun of ifuns.
Example
:IFUN.require_from('kink/iter/')
:nums <- IFUN.of(1 2 3)
:strs <- IFUN.of('foo' 'bar')
:bools <- IFUN.of(true false)
IFUN.each(IFUN.concat(IFUN.of($nums $strs $bools))){(:N)
stdout.print_line(N.repr)
}
# => 1 2 3 "foo" "bar" true false
6.63.15. IFUN.unconcat($ifun Chunk_size)¶
`unconcat` splits $ifun into vecs whose size is `Chunk_size`, and returns an ifun of those vecs.
If the size of $ifun is a finite number Chunk_size * N + R, where N and R are non-negative integers, the last R elements of $ifun will be discarded.
Precondition
$ifun must be an ifun.
`Chunk_size` must be a positive int num.
Example
:IFUN.require_from('kink/iter/')
:ns <- IFUN.of(1 2 3 4 5 6 7)
:chunks <- IFUN.unconcat($ns 2)
IFUN.each($chunks){(:Chunk)
stdout.print_line(Chunk.repr)
}
# Output:
# [1 2]
# [3 4]
# [5 6]
6.63.16. IFUN.cycle($ifun)¶
`cycle` returns an ifun which infinitely repeats the elements of $ifun.
If $ifun is empty, the result ifun will be also empty.
Precondition
$ifun must be an ifun.
Example
:IFUN.require_from('kink/iter/')
:flip_flop <- IFUN.cycle(IFUN.of(true false))
:filtered_pairs <- IFUN.filter(IFUN.zip(1.up.ifun $flip_flop)){([:N :Include?])
Include?
}
:filtered_nums <- IFUN.map($filtered_pairs){([:N :Include?]) N}
IFUN.each(IFUN.take_front($filtered_nums 5)){(:N)
stdout.print_line(N.repr)
}
# Output:
# 1
# 3
# 5
# 7
# 9
6.63.17. IFUN.of(...Elems)¶
`of` returns an ifun containing the elements of `Elems`.
Example
:IFUN.require_from('kink/iter/')
IFUN.each(IFUN.of(1 2 3 4 5)){(:N)
stdout.print_line(N.repr)
}
6.63.18. IFUN.join($front $back)¶
`join` makes an ifun concatenating two ifuns $front and $back.
The result ifun produces the elements of $front in the same order, and then the elements of $back in the same order.
Example
:IFUN.require_from('kink/iter/')
:joined <- IFUN.join(
IFUN.of(1 2 3)
IFUN.of(4 5 6)
)
IFUN.each($joined){(:N)
stdout.print_line(N.repr)
} # => 1 2 3 4 5 6
6.63.19. IFUN.zip($ifun ...Other_ifuns)¶
If `zip` is passed N ifuns, `zip` returns an ifun as long as the shortest of these ifuns, each element of which is an N-element vec comprised of the corresponding elements from the passed ifuns.
For example, if an ifun X has elements X1, X2, X3, ,,, , Y has elements Y1, Y2, Y3, ,,, , and Z has elements Z1, Z2, Z3, ,,, , zip(X Y Z) returns an ifun containing [X1 Y1 Z1], [X2 Y2 Z2], [X3 Y3 Z3], ,,, .
Preconditions
$ifun must be an ifun.
Each element of `Other_ifuns` must be an ifun.
Example
:IFUN.require_from('kink/iter/')
:zipped <- IFUN.zip(
IFUN.of(1 2 3 4 5)
IFUN.of('foo' 'bar' 'baz')
IFUN.of(true false true)
)
IFUN.each($zipped){(:Triple)
stdout.print_line(Triple.repr)
}
# Output:
# [1 "foo" true]
# [2 "bar" false]
# [3 "baz" true]
6.63.20. IFUN.lazy($make_ifun)¶
`lazy` returns an ifun, whose elements are equal to the ifun returned by $make_ifun.
$make_ifun is called when the result ifun is called.
Precondition
$make_ifun must be a thunk which returns an ifun.
Example
:IFUN.require_from('kink/iter/')
:count_down <- {(:N)
if(N < 0
{ IFUN.of() }
{ IFUN.join(IFUN.of(N) IFUN.lazy{ count_down(N - 1) }) }
)
}
IFUN.each(count_down(5)){(:N)
stdout.print_line(N.repr)
}
# => 5 4 3 2 1 0
6.63.21. IFUN.from_generator($generator)¶
`from_generator` makes an ifun of elements yielded in $generator.
$generator must take an unary fun $yield as the arg. When $yield is called with a val in invocation of $generator, that val will be an element of the result ifun. When the invocation of $generator returns, it is the end of the ifun.
$generator is called when the result ifun is called. The invocation of $generator is suspended when $yield is called. The invocation is resumed when the trailing ifun is called.
Example: make a finite length ifun
:IFUN.require_from('kink/iter/')
:ifun <- IFUN.from_generator{(:yield)
yield('foo')
yield('bar')
yield('baz')
}
IFUN.each($ifun){(:Str)
stdout.print_line(Str)
}
# Output:
# foo
# bar
# baz
Example: make an infinite length ifun
:IFUN.require_from('kink/iter/')
:ifun <- IFUN.from_generator{(:yield)
:loop <- {(:N)
yield(N)
loop(N + 1)
}
loop(1)
}
IFUN.each(IFUN.take_front($ifun 5)){(:N)
stdout.print_line(N.repr)
}
# Output:
# 1
# 2
# 3
# 4
# 5
6.63.22. IFUN.from_each(Eacher)¶
`from_each` makes an ifun of values which are enumerated in Eacher.each.
The invocation of `each` is suspended and resumed for evaluation of each element of the ifun.
Precondition
`Eacher` must support each($consume) method, which is called to enumerate each element of `Eacher`.
Example
:IFUN.require_from('kink/iter/')
:take_five <- IFUN.from_each([1 2 3 4 5])
IFUN.each($take_five){(:N)
stdout.print_line(N.repr)
}
# => 1 2 3 4 5