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