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