多段階選抜 (Julia/Rust)


|多段階選抜|解答日|シリーズ: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|

ついに20言語到達( **すべて無限リスト** )。

## Julia

- Goからの移植。
- juliac.jl対応してます。

```julia:tyama_hena24_enum.jl
#!/usr/bin/env julia

# http://qiita.com/Nabetani/items/1c83005a854d2c6cbb69
# http://nabetani.sakura.ne.jp/hena/ord24eliseq/

function isqrt(n::Int)
	if n<=0
		return 0
	end
	if n<4
		return 1
	end
	local x=0
	local y=n
	while x!=y&&x+1!=y
		x=y
		y=(n÷y+y)÷2
	end
	return x
end

function icbrt(n::Int)
	if n<0
		return -icbrt(-n)
	end
	if n==0
		return 0
	end
	if n<8
		return 1
	end
	local x=0
	local y=n
	while x!=y&&x+1!=y
		x=y
		y=(n÷y÷y+y*2)÷3
	end
	return x
end

function is_sq(n::Int)
	local x=isqrt(n)
	return x*x==n
end
function is_cb(n::Int)
	local x=icbrt(n)
	return x*x*x==n
end
is_multiple(i::Int,n::Int) = i%n==0
is_le(i::Int,n::Int) = i<=n

function generate()
	local ch = Channel{Int}(8)
	function _producer()
		local i=1
		while true
			put!(ch,i)
			i+=1
		end
	end
	@async _producer()
	ch
end

function drop_prev(check::Function,prev::Channel{Int})
	local ch = Channel{Int}(8)
	function _producer()
		local a=take!(prev)
		local b=take!(prev)
		while true
			if !check(b)
				put!(ch,a)
			end
			a=b
			b=take!(prev)
		end
	end
	@async _producer()
	return ch
end

function drop_next(check,prev::Channel{Int})
	local ch = Channel{Int}(8)
	function _producer()
		local a=take!(prev)
		local b=take!(prev)
		put!(ch,a)
		while true
			if !check(a)
				put!(ch,b)
			end
			a=b
			b=take!(prev)
		end
	end
	@async _producer()
	return ch
end

function drop_n(check,n::Int,prev::Channel{Int})
	local ch = Channel{Int}(8)
	function _producer()
		local i=0
		while true
			i+=1
			a=take!(prev)
			if !check(i,n)
				put!(ch,a)
			end
		end
	end
	@async _producer()
	return ch
end

Base.@ccallable function julia_main(args::Vector{String})::Cint
	local f=Dict(
		'S' => prev -> drop_next(is_sq,prev),
		's' => prev -> drop_prev(is_sq,prev),
		'C' => prev -> drop_next(is_cb,prev),
		'c' => prev -> drop_prev(is_cb,prev),
		'h' => prev -> drop_n(is_le,100,prev)
	)
	for j in 2:9
		#ラムダ式のキャプチャはバグらないみたいですね
		f[j+'0']=prev -> drop_n(is_multiple,j,prev)
	end

	local line=readline(stdin)
	while line!=""
		line=rstrip(line)
		#cS => f['S'](f['c'](generate()))
		local ch = generate()
		for c in line
			ch=f[c](ch)
		end
		for i in 0:9
			if i>0
				print(",")
			end
			a=take!(ch)
			print(a)
		end
		print("\n")
		flush(stdout)
		line=readline(stdin)
	end
	return 0
end

if get(ENV, "COMPILE_STATIC", "false") == "false"
	julia_main(ARGS)
end
```

## Rust

- (1.33時点で)nightly専用です
- 1.45で動作するように修正しました

```rs:tyama_hena24_enum.rs
// http://qiita.com/Nabetani/items/1c83005a854d2c6cbb69
// http://nabetani.sakura.ne.jp/hena/ord24eliseq/

#![feature(generators, generator_trait)]
use std::ops::{Generator, GeneratorState};

use std::io::BufRead;

type BoxGeneratorI64Send = Box<dyn Generator<Yield=i64,Return=()>+Unpin+Send>;

fn isqrt(n:i64) -> i64{
	if n<=0 {
		return 0;
	}
	if n<4 {
		return 1;
	}
	let mut x=0;
	let mut y=n;
	while x!=y&&x+1!=y {
		x=y;
		y=(n/y+y)/2;
	}
	return x;
}

fn icbrt(n:i64) -> i64{
	if n<0 {
		return -icbrt(-n);
	}
	if n==0 {
		return 0;
	}
	if n<8 {
		return 1;
	}
	let mut x=0;
	let mut y=n;
	while x!=y&&x+1!=y {
		x=y;
		y=(n/y/y+y*2)/3;
	}
	return x;
}

fn is_sq(n:i64) -> bool{
	let x=isqrt(n);
	return x*x==n;
}
fn is_cb(n:i64) -> bool{
	let x=icbrt(n);
	return x*x*x==n;
}
fn is_multiple(i:i64,n:i64) -> bool{i%n==0}
fn is_le(i:i64,n:i64) -> bool{i<=n}

fn next<T>(mut gen:impl Generator<Yield=T,Return=()>+Unpin) -> Option<T>{
	// acknowledgement: https://github.com/tinaun/gen-iter/blob/master/src/lib.rs
	match std::pin::Pin::new(&mut gen).resume(()) {
		GeneratorState::Yielded(n) => Some(n),
		GeneratorState::Complete(_) => None,
	}
}

fn generate() -> BoxGeneratorI64Send{
	return Box::new(move || { // move is optional in this line
		let mut i=1;
		loop{
			yield i;
			i+=1;
		}
	});
}

fn drop_prev(check:fn(i64)->bool,mut prev:BoxGeneratorI64Send) -> BoxGeneratorI64Send{
	return Box::new(move || {
		let mut a=next(&mut prev).unwrap();
		let mut b=next(&mut prev).unwrap();
		loop{
			if !check(b) {
				yield a;
			}
			a=b;
			b=next(&mut prev).unwrap();
		}
	});
}

fn drop_next(check:fn(i64)->bool,mut prev:BoxGeneratorI64Send) -> BoxGeneratorI64Send{
	return Box::new(move || {
		let mut a=next(&mut prev).unwrap();
		let mut b=next(&mut prev).unwrap();
		yield a;
		loop{
			if !check(a) {
				yield b;
			}
			a=b;
			b=next(&mut prev).unwrap();
		}
	});
}

fn drop_n(check:fn(i64,i64)->bool,n:i64,mut prev:BoxGeneratorI64Send) -> BoxGeneratorI64Send{
	return Box::new(move || {
		let mut i=0;
		loop{
			i+=1;
			let a=next(&mut prev).unwrap();
			if !check(i,n) {
				yield a;
			}
		}
	});
}

fn main() {
	// cannot initialize Generator trait's HashMap using vec![].into_iter().collect() [E0277]
	let mut f:std::collections::HashMap<char,fn(BoxGeneratorI64Send)->BoxGeneratorI64Send> = std::collections::HashMap::new();
	f.insert('S',|e|{drop_next(is_sq,e)});
	f.insert('s',|e|{drop_prev(is_sq,e)});
	f.insert('C',|e|{drop_next(is_cb,e)});
	f.insert('c',|e|{drop_prev(is_cb,e)});
	f.insert('h',|e|{drop_n(is_le,100,e)});

	//due to complicated lifetime, for now I don't use for-loop here
	f.insert('2',|e|{drop_n(is_multiple,2,e)});
	f.insert('3',|e|{drop_n(is_multiple,3,e)});
	f.insert('4',|e|{drop_n(is_multiple,4,e)});
	f.insert('5',|e|{drop_n(is_multiple,5,e)});
	f.insert('6',|e|{drop_n(is_multiple,6,e)});
	f.insert('7',|e|{drop_n(is_multiple,7,e)});
	f.insert('8',|e|{drop_n(is_multiple,8,e)});
	f.insert('9',|e|{drop_n(is_multiple,9,e)});

	let stdin = std::io::stdin();
	for line in stdin.lock().lines() {
	match line {
		Ok(s) => {
			let mut z=generate();
			for c in s.trim().chars() {
				z=f[&c](z);
			}
			for i in 0..10 {
				if i>0 {
					print!(",");
				}
				print!("{}", next(&mut z).unwrap());
			}
			println!("");
		},
		Err(_) => ()
	}}
}
```

### 220329

Swift編で得た知見をもとに、drop_prev等をクロージャを使ったものに変更しました。(nightlyは不要になりました)

```rs
// http://qiita.com/Nabetani/items/1c83005a854d2c6cbb69
// http://nabetani.sakura.ne.jp/hena/ord24eliseq/

use std::io::BufRead;

type BoxFnMutI64 = Box<dyn FnMut()->i64>;

fn isqrt(n:i64) -> i64{
	if n<=0 {
		return 0;
	}
	if n<4 {
		return 1;
	}
	let mut x=0;
	let mut y=n;
	while x!=y&&x+1!=y {
		x=y;
		y=(n/y+y)/2;
	}
	return x;
}

fn icbrt(n:i64) -> i64{
	if n<0 {
		return -icbrt(-n);
	}
	if n==0 {
		return 0;
	}
	if n<8 {
		return 1;
	}
	let mut x=0;
	let mut y=n;
	while x!=y&&x+1!=y {
		x=y;
		y=(n/y/y+y*2)/3;
	}
	return x;
}

fn is_sq(n:i64) -> bool{
	let x=isqrt(n);
	return x*x==n;
}
fn is_cb(n:i64) -> bool{
	let x=icbrt(n);
	return x*x*x==n;
}
fn is_multiple(i:i64,n:i64) -> bool{i%n==0}
fn is_le(i:i64,n:i64) -> bool{i<=n}

fn generate() -> BoxFnMutI64{
	let mut i=0;
	return Box::new(move || {
		i+=1;
		return i
	})
}

fn drop_prev(check:fn(i64)->bool,mut prev:BoxFnMutI64) -> BoxFnMutI64{
	let mut a = 0;
	let mut b = prev();
	return Box::new(move || {
		loop {
			a = b;
			b = prev();
			if !check(b) {
				return a
			}
		}
	})
}

fn drop_next(check:fn(i64)->bool,mut prev:BoxFnMutI64) -> BoxFnMutI64{
	let mut first = true;
	let mut a = 0;
	let mut b = 0;
	return Box::new(move || {
		loop {
			a = b;
			b = prev();
			if first || !check(a) {
				first = false;
				return b
			}
		}
	})
}

fn drop_n(check:fn(i64,i64)->bool,n:i64,mut prev:BoxFnMutI64) -> BoxFnMutI64{
	let mut i=0;
	return Box::new(move || {
		loop{
			i+=1;
			let a=prev();
			if !check(i,n) {
				return a
			}
		}
	})
}

fn main() {
	// cannot initialize Generator trait's HashMap using vec![].into_iter().collect() [E0277]
	let mut f:std::collections::HashMap<char,fn(BoxFnMutI64)->BoxFnMutI64> = std::collections::HashMap::new();
	f.insert('S',|e|{drop_next(is_sq,e)});
	f.insert('s',|e|{drop_prev(is_sq,e)});
	f.insert('C',|e|{drop_next(is_cb,e)});
	f.insert('c',|e|{drop_prev(is_cb,e)});
	f.insert('h',|e|{drop_n(is_le,100,e)});

	//due to complicated lifetime, for now I don't use for-loop here
	f.insert('2',|e|{drop_n(is_multiple,2,e)});
	f.insert('3',|e|{drop_n(is_multiple,3,e)});
	f.insert('4',|e|{drop_n(is_multiple,4,e)});
	f.insert('5',|e|{drop_n(is_multiple,5,e)});
	f.insert('6',|e|{drop_n(is_multiple,6,e)});
	f.insert('7',|e|{drop_n(is_multiple,7,e)});
	f.insert('8',|e|{drop_n(is_multiple,8,e)});
	f.insert('9',|e|{drop_n(is_multiple,9,e)});

	let stdin = std::io::stdin();
	for line in stdin.lock().lines() {
	match line {
		Ok(s) => {
			let mut z=generate();
			for c in s.trim().chars() {
				z=f[&c](z);
			}
			for i in 0..10 {
				if i>0 {
					print!(",");
				}
				print!("{}", z());
			}
			println!("");
		},
		Err(_) => ()
	}}
}
```