多段階選抜 (Crystal)


|多段階選抜|解答日|シリーズ:yieldの練習/ジェネレータを入れ子に/整数平方根・立方根の実装|
|:--|:--|:--|
|問題|　|http://nabetani.sakura.ne.jp/hena/ord24eliseq/<br>https://qiita.com/Nabetani/items/1c83005a854d2c6cbb69|
|Ruby|2014/8/2(当日)|https://qiita.com/cielavenir/items/9f15e29b73ecf98968a5|
|C#/Python|2014/8/4|https://qiita.com/cielavenir/items/a1156e6a4f71ddbe5dcb|
| |　|ここから上はdrop_prev_square/drop_prev_cubicをまとめる前の答案|
|Go/C#/Ruby/Python|2014/8/5|https://qiita.com/cielavenir/items/2a685d3080862f2c2c47|
|PHP/JavaScript|2014/9/9|https://qiita.com/cielavenir/items/28d613ac3823afbf8407|
|VB|2014/9/10|https://qiita.com/cielavenir/items/cb7266abd30eadd71c04|
|D|2015/12/21|https://qiita.com/cielavenir/items/47c9e50ee60bef2847ec|
|Perl|2017/3/10|https://qiita.com/cielavenir/items/6dfbff749d833c0fd423|
|Lua|2017/3/13|https://qiita.com/cielavenir/items/c60fe7e8da73487ba062|
|C++20(TS)|2017/3/15|https://qiita.com/cielavenir/items/e1129ca185008f49cbab (MSVC)<br>https://qiita.com/cielavenir/items/1cfa90d73d11bb7dc3d4 (clang)|
|F#|2017/3/17|https://qiita.com/cielavenir/items/a698d6a26824ff53de81|
|Boo/Nemerle|2017/5/13|https://qiita.com/cielavenir/items/e2a783f0fe4b0fe0ed48|
|Perl6|2017/5/15|https://qiita.com/cielavenir/items/656ea17fa96c865c4498|
|Kotlin|2017/5/25|https://qiita.com/cielavenir/items/9c46ce8d9d12e51de285|
|Crystal|2018/5/8|https://qiita.com/cielavenir/items/1815bfa6a860fd1f90db|
|MoonScript|2018/6/16|https://qiita.com/cielavenir/items/8b03cce0386f4537b5ad|
|Julia/Rust|2018/12/20|https://qiita.com/cielavenir/items/3ddf72b06d625da0c4a5|
|Nim|2018/12/26|https://qiita.com/cielavenir/items/5728944867e609fd52a7|
|Tcl|2018/12/31|https://qiita.com/cielavenir/items/76cbd9c2022b48c9a2c9|
|Pascal/Cobra|2019/1/16|https://qiita.com/cielavenir/items/81b81baf8dfc1f877903|
|Icon|2019/1/17|https://qiita.com/cielavenir/items/889622dcc721f5a4da24|
|Swift|2020/5/31|https://qiita.com/cielavenir/items/3b0b84a218e35d538f7f|
|Java/Groovy/Scala|2020/5/31|https://qiita.com/cielavenir/items/7f058203a8fd03b65870|
|V|2020/10/17|https://qiita.com/cielavenir/items/df30a6c101a97a713df5|
|Zig/Zen|2020/10/17|https://qiita.com/cielavenir/items/9cced9e4a94dcd70df0f|
|Pike|2020/11/2|https://qiita.com/cielavenir/items/3a8248f41611302b34fd|
|Vala/Smalltalk|2020/11/29|https://qiita.com/cielavenir/items/085dabe593cd916af5e8|
|Objective-C|2020/11/30|https://qiita.com/cielavenir/items/a1736e38789a3dd5cc5a|
|Ruby(Ractor)|2021/1/2|https://qiita.com/cielavenir/items/f493c6d512b63cc571cc|
|Python(_xxsubinterpreters)|2021/6/29|https://qiita.com/cielavenir/items/f1f581a055db918954f1|
|Falcon/Scheme|2021/9/5|https://qiita.com/cielavenir/items/c13d12cf44f0d17f4a94|
|Clojure/Lisp|2021/9/7|https://qiita.com/cielavenir/items/7458ba076f4e5bc0f196|
|(icbrtの実装に関する)補題|2017/5/11|整数除算であってもn/(x*y)はn/x/yに等しい(ことの証明)<br>https://qiita.com/cielavenir/items/21a6711afd6be8c18c55|

spawnの構文はGoっぽい。

それはともかく。2から9まで配列にProcをセットする部分で、別のProcを噛ませないと、 **internal errorで** 落ちた。びっくり。

```cr:tyama_hena24_enum.cr
#!/usr/bin/env crystal
#http://qiita.com/Nabetani/items/1c83005a854d2c6cbb69
#http://nabetani.sakura.ne.jp/hena/ord24eliseq/

def isqrt(n)
	return 0 if n<=0
	return 1 if n<4 # 1
	x,y=0,n
	while x!=y&&x+1!=y
		x,y=y,(n//y+y)//2
	end
	x
end
def icbrt(n)
	return -icbrt(-n) if n<0
	return 0 if n==0
	return 1 if n<8 # 1,7
	x,y=0,n
	while x!=y&&x+1!=y
		x,y=y,(n//y//y+y*2)//3
	end
	x
end

def generate : Channel(Int32)
	nxt=Channel(Int32).new
	i=1
	spawn{
		loop{
			nxt.send(i)
			i+=1
		}
	}
	nxt
end

def drop_prev(check : Int32 -> Bool,prev : Channel(Int32)) : Channel(Int32)
	a=prev.receive
	b=prev.receive
	nxt=Channel(Int32).new
	spawn{
		loop{
			nxt.send(a) if !check.call(b)
			a,b=b,prev.receive
		}
	}
	nxt
end

def drop_next(check : Int32 -> Bool,prev : Channel(Int32)) : Channel(Int32)
	a=prev.receive
	b=prev.receive
	nxt=Channel(Int32).new
	spawn{
		nxt.send(a)
		loop{
			nxt.send(b) if !check.call(a)
			a,b=b,prev.receive
		}
	}
	nxt
end

def drop_n(check : Int32, Int32 -> Bool,n : Int,prev : Channel(Int32)) : Channel(Int32)
	nxt=Channel(Int32).new
	i=0
	spawn{
		loop{
			i+=1
			a=prev.receive
			nxt.send(a) if !check.call(i,n)
		}
	}
	nxt
end

is_sq=->(n : Int32){isqrt(n)**2==n}
is_cb=->(n : Int32){icbrt(n)**3==n}
is_multiple=->(i : Int32,n : Int32){i%n==0}
is_le=->(i : Int32,n : Int32){i<=n}

f={
	'S' => ->(enm : Channel(Int32)){drop_next(is_sq,enm)},
	's' => ->(enm : Channel(Int32)){drop_prev(is_sq,enm)},
	'C' => ->(enm : Channel(Int32)){drop_next(is_cb,enm)},
	'c' => ->(enm : Channel(Int32)){drop_prev(is_cb,enm)},
	'h' => ->(enm : Channel(Int32)){drop_n(is_le,100,enm)},
}
(2..9).each{|i|f[i.to_s[0]]=->(n : Int32){
	->(enm : Channel(Int32)){drop_n(is_multiple,n,enm)}
}.call(i)}

#Using below one causes internal error
#Case 0: Module validation failed: inlinable function call in a function with debug info must have a !dbg location
#  %156 = call i8* @__crystal_malloc64(i64 ptrtoint (%closure_7* getelementptr (%closure_7, %closure_7* null, i32 1) to i64))
#
#Crystal::CodeGenVisitor#finish:Nil
#Crystal::Compiler#codegen<Crystal::Program, Crystal::ASTNode+, Array(Crystal::Compiler::Source), String>:(Tuple(Array(Crystal::Compiler::CompilationUnit), Array(String)) | Nil)
#Crystal::Compiler#compile<Array(Crystal::Compiler::Source), String>:Crystal::Compiler::Result
#Crystal::Command#run_command<Bool>:Nil
#Crystal::Command#run:(Bool | Crystal::Compiler::Result | IO::FileDescriptor | Nil)
#main

#(2..9).each{|i|f[i.to_s[0]]=
#	->(enm : Channel(Int32)){drop_n(is_multiple,i,enm)}
#}

while s=gets
	#cS => f['S'].call(f['c'].call(generate))
	enm=s.chomp.chars.reduce(generate){|s,e|f[e].call(s)}
	10.times{|i|
		print ',' if i>0
		print enm.receive
	}
	puts
	STDOUT.flush
end
```