6.63. kink/iter/IFUN

ifunの操作。

“ifun”は“iterator function”、つまりイテレータ関数の略語である。ifunは有限長、または無限長の値のストリームにおけるポインタとして動作する関数である。

通常、ifunを直接使うよりも、ifunのラッパであるiterを使ったほうが便利だ。iterについてはkink/iter/ITERを見よ。

仕様

ifunは2引数の関数で、$procと$finを引数に取る。要素が存在する場合、ifunは$procを末尾呼び出ししなければならない。要素がなければ、ifunは$finを引数なしで末尾呼び出ししなければならない。

$procは2引数の関数で、Headと$tailを引数に取る。ifunは最初の要素をHeadとして、Headより後ろの要素を含む後続のifunを$tailとして渡す。

$finはサンクであり、ifunに要素がないときに末尾呼び出しされる。

次のプログラムでは、make_vec_ifunが、Vecの要素をたどるifunを作る。

: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 }
    )
  }
}

ifunを作ってみよう。

:nums_ifun <- make_vec_ifun([100 200 300])

IFUN.eachを使って、$nums_ifunの要素をたどることができる。

:IFUN.require_from('kink/iter/')

IFUN.each(
  $nums_ifun
  {(:N) stdout.print_line(N.repr) }
)
# Output:
#   100
#   200
#   300

ifunの要素をマッピングする別のifunも作れる。

:doubled_ifun <- IFUN.map($nums_ifun {(:N) N * 2 })
IFUN.each(
  $doubled_ifun
  {(:N) stdout.print_line(N.repr) }
)
# Output:
#   200
#   400
#   600

要素を足し合わせてみよう。

:Sum <- IFUN.fold($nums_ifun 0 {(:X :Y) X + Y })
stdout.print_line(Sum.repr) # => 600

6.63.1. IFUN.each($ifun $consume)

eachは$ifunのそれぞれの要素について$consumeを呼び出し、最後の$consumeの呼び出しの戻り値を戻す。

$ifunが要素を持たない場合、eachはnadaを戻す。

事前条件

$ifunはifunでなければならない。

$consumeは引数をひとつ取る関数でなければならない。

: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はN番目の要素がtransform($ifunのN番目の要素)であるようなifunを戻す。

事前条件

$ifunはifunでなければならない。

$transformは引数をひとつ取らなければならない。

: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は、to_ifun($ifunの要素)の結果であるifunを結合したifunを戻す。

事前条件

$ifunはifunでなければならない。

$to_ifunは引数をひとつ取り、ifunを戻さなければならない。

: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は$ifunの要素のうち$include?を満たすものを、ifunとして戻す。要素の順序は変わらない。

事前条件

$ifunはifunでなければならない。

$include?は述語でなければならない。

: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は$ifunの要素のうち$counted?を満たす要素の数を戻す。

結果は整数のnum値である。

事前条件

$ifunはifunでなければならない。

$counted?は述語でなければならない。

: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はInitを種として、$ifunの要素を畳み込んだ値を戻す。

$ifunの要素がE1, E2, ,,, En_1, Enであるとき、foldはcombine(combine(,,,combine(combine(Init E1) E2),,, En_1) En)を戻す。

$ifunが空の場合、foldはInitを戻す。

事前条件

$ifunはifunでなければならない。

$combineはふたつの引数を取らなければならない。

: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は$ifunの要素を相互に畳み込む。

$ifunの要素がE1, E2, E3, ,,, En_1, Enであるとき、reduceはcombine(combine(,,,combine(combine(E1 E2) E3),,, En_1) En)を戻す。

$ifunの要素がEひとつであるとき、reduceはEを戻す。

$ifunが要素を持たず、$empty_fallbackが与えられているとき、reduceは$empty_fallbackを引数なしで末尾呼び出しする。

$ifunが要素を持たず、$empty_fallbackが与えられていないとき、reduceは例外を投げる。

事前条件

$ifunはifunでなければならない。

$combineはふたつの引数を取らなければならない。

$empty_fallbackはサンクでなければならない。

: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は$ifunの最初のN個の要素を含むifunを戻す。$ifunの要素がN個より少ないときは、すべての要素を含むifunを戻す。

事前条件

$ifunはifunでなければならない。

Nは整数のnum値でなければならない。

: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は$ifunの最初のN個の要素を除いたifunを戻す。$ifunの要素がN個より少ないときは、空のifunを戻す。

事前条件

$ifunはifunでなければならない。

Nは整数のnum値でなければならない。

: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は、すべての要素が$include?を満たすような、$ifunの最長の先頭部分を、ifunとして戻す。

事前条件

$ifunはifunでなければならない。

$include?は述語でなければならない。

: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は、すべての要素が$exclude?を満たすような、$ifunの最長の先頭部分を取り除き、残りをifunとして戻す。

事前条件

$ifunはifunでなければならない。

$exclude?は述語でなければならない。

: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?は、$ifunのすべての要素が$match?を満たすときにtrueを戻し、そうでないときにfalseを戻す。

$ifunの要素数が無限の場合、all?は戻ることが保証されない。

事前条件

$ifunはifunでなければならない。

$match?は述語でなければならない。

: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?は$ifunのひとつ以上の要素が$match?を満たすときにtrueを戻し、そうでないときにfalseを戻す。

$ifunの要素数が無限の場合、any?は戻ることが保証されない。

事前条件

$ifunはifunでなければならない。

$match?は述語でなければならない。

: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は$ifun_of_ifunsに含まれるifunの要素を連結する。

事前条件

$ifun_of_ifunsはifunを要素に持つifunでなければならない。

: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は$ifunを、長さがChunk_sizeであるようなベクタに分割し、それらベクタを要素に持つifunを戻す。

$ifunの長さが有限の数Chunk_size * N + R, ただしNとRは非負の整数, であるとき、$ifunの最後のR個の要素は捨てられる。

事前条件

$ifunはifunでなければならない。

Chunk_sizeは正の整数のnum値でなければならない。

: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は$ifunの要素を無限に繰り返したifunを戻す。

$ifunが空の場合、結果のifunも空になる。

事前条件

$ifunはifunでなければならない。

: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はElemsの要素を持つifunを戻す。

: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はふたつのifun、$frontと$backをつなげたifunを戻す。

結果のifunは、$frontの要素を順番通りに、それについで$backの要素を順番通りに持つ。

: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)

zipにN個のifunが渡されたとき、zipは、長さが引数のifunの中で最短のものと同じ長さであり、それぞれの要素がN個の要素のvecで、そのvecが渡されたifunの対応する要素からなるようなifunを戻す。

たとえば、ifun XがX1, X2, X3, ,,,を要素に持ち、YがY1, Y2, Y3, ,,,,を要素に持ち、ZがZ1, Z2, Z3, ,,,,を要素に持つ場合、zip(X Y Z)は[X1 Y1 Z1], [X2 Y2 Z2], [X3 Y3 Z3], ,,,を持つifunを戻す。

事前条件

$ifunはifunでなければならない。

Other_ifunsのそれぞれの要素はifunでなければならない。

: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は、$make_funが戻すifunと同じ要素を持つifunを戻す。

$make_funは、結果のifunが呼ばれたときに呼ばれる。

事前条件

$make_ifunはifunを戻すサンクでなければならない。

: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は$generatorの中で算出された要素を含むifunを戻す。

$generatorは、引数ひとつの関数$yieldを引数に取らなければならない。$generatorの呼び出しの中で$yieldが引数とともに呼ばれると、その引数が結果のifunの要素になる。$generatorの呼び出しが終わると、そこがifunの末尾になる。

$generatorはifunが呼ばれた時に呼び出される。$generatorの呼び出しは、$yieldが呼ばれた時に中断される。呼び出しは、後続するifunが呼ばれた時に再開される。

例: 有限長の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

例: 無限長の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はEacher.eachで列挙される値を要素に持つifunを戻す。

eachの呼び出しは、ifunの要素の評価ごとに中断、再開される。

事前条件

Eacherはeach($consume)メソッドをサポートしなければならない。eachメソッドは、Eacherの要素を列挙するために呼ばれる。

: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