多段階選抜 (Vala/Smalltalk)


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

35言語到達(全て無限リスト)です。。(Zig/Zenは別カウントにしました)

## Vala

```vala:tyama_hena24_enum.vala
//usr/bin/env vala --pkg gee-0.8 --pkg gio-2.0 "$0" "$@";exit

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

using Gee;

abstract class Generator<G> {
	// http://valajournal.blogspot.com/2011/07/generators-in-vala.html
	private bool consumed;
	private G value;
	private SourceFunc callback;

	protected async void helper () {
		yield generate ();
		consumed = true;
	}

	protected abstract async void generate ();

	protected async void feed (G value) {
		this.value = value;
		this.callback = feed.callback;
		yield;
	}

	public bool next () {
		return !consumed;
	}

	public G get () {
		var result = value;
		callback ();
		return result;
	}

	public Generator<G> iterator () {
		return this;
	}
}

int isqrt(int n){
	if(n<=0)return 0;
	if(n<4)return 1;
	int x=0,y=n;
	for(;x!=y&&x+1!=y;){x=y;y=(n/y+y)/2;}
	return x;
}
int icbrt(int n){
	if(n<0)return -icbrt(-n);
	if(n==0)return 0;
	if(n<8)return 1;
	int x=0,y=n;
	for(;x!=y&&x+1!=y;){x=y;y=(n/y/y+y*2)/3;}
	return x;
}

class mygenerate_impl:Generator<int>{
	public mygenerate_impl(){
		helper();
	}
	protected override async void generate(){
		for(int i=1;;i++){
			yield feed(i);
		}
	}
}
Generator<int> mygenerate(){return new mygenerate_impl();}

static delegate bool dbi(int a);
class drop_prev_impl:Generator<int>{
	dbi check;
	Generator<int> prev;
	public drop_prev_impl(dbi _check, Generator<int> _prev){
		check=_check;
		prev=_prev;
		helper();
	}
	protected override async void generate(){
		int a=prev.get();
		int b=prev.get();
		for(;;){
			if(!check(b))yield feed(a);
			a=b;
			b=prev.get();
		}
	}
}
Generator<int> drop_prev(dbi check,Generator<int> prev){return new drop_prev_impl(check,prev);}

class drop_next_impl:Generator<int>{
	dbi check;
	Generator<int> prev;
	public drop_next_impl(dbi _check, Generator<int> _prev){
		check=_check;
		prev=_prev;
		helper();
	}
	protected override async void generate(){
		int a=prev.get();
		int b=prev.get();
		yield feed(a);
		for(;;){
			if(!check(a))yield feed(b);
			a=b;
			b=prev.get();
		}
	}
}
Generator<int> drop_next(dbi check,Generator<int> prev){return new drop_next_impl(check,prev);}

static delegate bool dbii(int a,int b);
class drop_n_impl:Generator<int>{
	dbii check;
	int n;
	Generator<int> prev;
	public drop_n_impl(dbii _check, int _n, Generator<int> _prev){
		check=_check;
		n=_n;
		prev=_prev;
		helper();
	}
	protected override async void generate(){
		int i=0;
		for(;;){
			i++;
			int a=prev.get();
			if(!check(i,n))yield feed(a);
		}
	}
}
Generator<int> drop_n(dbii check,int n,Generator<int> prev){return new drop_n_impl(check,n,prev);}

bool is_sq(int n){
	int x=isqrt(n);
	return x*x==n;
}
bool is_cb(int n){
	int x=icbrt(n);
	return x*x*x==n;
}
bool is_multiple(int i,int n){return i%n==0;}
bool is_le(int i,int n){return i<=n;}

static delegate Generator<int> dgg(Generator<int> a);
void main(){
	var f=new HashMap<char,dgg>();
	f.set('S',(e)=>{return drop_next(is_sq,e);});
	f.set('s',(e)=>{return drop_prev(is_sq,e);});
	f.set('C',(e)=>{return drop_next(is_cb,e);});
	f.set('c',(e)=>{return drop_prev(is_cb,e);});
	f.set('h',(e)=>{return drop_n(is_le,100,e);});
	f.set('2',(e)=>{return drop_n(is_multiple,2,e);});
	f.set('3',(e)=>{return drop_n(is_multiple,3,e);});
	f.set('4',(e)=>{return drop_n(is_multiple,4,e);});
	f.set('5',(e)=>{return drop_n(is_multiple,5,e);});
	f.set('6',(e)=>{return drop_n(is_multiple,6,e);});
	f.set('7',(e)=>{return drop_n(is_multiple,7,e);});
	f.set('8',(e)=>{return drop_n(is_multiple,8,e);});
	f.set('9',(e)=>{return drop_n(is_multiple,9,e);});

	for(string line;(line = stdin.read_line())!=null;){
		bool first=true;
		//cS => f['S'](f['c'](generate()))
		//auto z=reduce!((s,e)=>f[e](s))(generate(),line);

		var z=mygenerate();
		foreach(uint8 e in line.data){
			// called object type 'gpointer' (aka 'void *') is not a function or function pointer
			// z=f[(char)e](z);

			if(e=='S')z=drop_next(is_sq,z);
			if(e=='s')z=drop_prev(is_sq,z);
			if(e=='C')z=drop_next(is_cb,z);
			if(e=='c')z=drop_prev(is_cb,z);
			if(e=='h')z=drop_n(is_le,100,z);
			if(e=='2')z=drop_n(is_multiple,2,z);
			if(e=='3')z=drop_n(is_multiple,3,z);
			if(e=='4')z=drop_n(is_multiple,4,z);
			if(e=='5')z=drop_n(is_multiple,5,z);
			if(e=='6')z=drop_n(is_multiple,6,z);
			if(e=='7')z=drop_n(is_multiple,7,z);
			if(e=='8')z=drop_n(is_multiple,8,z);
			if(e=='9')z=drop_n(is_multiple,9,z);
		}
		for(int i=0;i<10;i++){
			int n=z.get();
			if(!first)stdout.printf("%c",',');
			first=false;
			stdout.printf("%d",n);
		}
		stdout.printf("\n");
		stdout.flush();
	}
}
```

## Smalltalk

```smalltalk:tyama_hena24_enum.st
#!/usr/bin/env gst

isqrt := [:n |
	|x y|
	(n<=0)ifTrue:[0.]ifFalse:[
		(n<4)ifTrue:[1.]ifFalse:[
			x:=0.
			y:=n.
			[x~~y and: [x+1~~y]]whileTrue:[
				x:=y.
				y:=(n//y+y)//2.
			].
			x.
		].
	].
].

icbrt := [:n |
	|x y|
	(n<0)ifTrue:[0-(icbrt value: 0-n).]ifFalse:[
		(n==0)ifTrue:[0.]ifFalse:[
			(n<8)ifTrue:[1.]ifFalse:[
				x:=0.
				y:=n.
				[x~~y and: [x+1~~y]]whileTrue:[
					x:=y.
					y:=(n//y//y+y+y)//3. "somehow n//y//y+y*2 does not work"
				].
				x.
			].
		].
	].
].

generate := [
	Generator on:[:y|
		i:=1.
		[true]whileTrue:[
			y yield: i.
			i:=i+1.
		].
	].
].

drop_prev := [:check :prev|
	Generator on:[:y|
		|a b|
		a:=prev next.
		b:=prev next.
		[true]whileTrue:[
			(check value: b)ifFalse:[y yield: a].
			a:=b.
			b:=prev next.
		].
	].
].

drop_next := [:check :prev|
	Generator on:[:y|
		|a b|
		a:=prev next.
		b:=prev next.
		y yield: a.
		[true]whileTrue:[
			(check value: a)ifFalse:[y yield: b].
			a:=b.
			b:=prev next.
		].
	].
].

drop_n := [:check :n :prev|
	Generator on:[:y|
		|i a|
		i:=0.
		[true]whileTrue:[
			i:=i+1.
			a:=prev next.
			(check value: i value: n)ifFalse:[y yield: a].
		].
	].
].

is_sq := [:n|
	|x|
	x:=isqrt value: n.
	x*x==n.
].
is_cb := [:n|
	|x|
	x:=icbrt value: n.
	x*x*x==n.
].
is_multiple := [:i :n|
	i\\n==0.
].
is_le := [:i :n|
	i<=n.
].

main := [:input|
	|f|
	f := Dictionary new.
	f at: 'S' put: [:e|drop_next value: is_sq value: e.].
	f at: 's' put: [:e|drop_prev value: is_sq value: e.].
	f at: 'C' put: [:e|drop_next value: is_cb value: e.].
	f at: 'c' put: [:e|drop_prev value: is_cb value: e.].
	f at: 'h' put: [:e|drop_n value: is_le value: 100 value: e.].
	f at: '2' put: [:e|drop_n value: is_multiple value: 2 value: e.].
	f at: '3' put: [:e|drop_n value: is_multiple value: 3 value: e.].
	f at: '4' put: [:e|drop_n value: is_multiple value: 4 value: e.].
	f at: '5' put: [:e|drop_n value: is_multiple value: 5 value: e.].
	f at: '6' put: [:e|drop_n value: is_multiple value: 6 value: e.].
	f at: '7' put: [:e|drop_n value: is_multiple value: 7 value: e.].
	f at: '8' put: [:e|drop_n value: is_multiple value: 8 value: e.].
	f at: '9' put: [:e|drop_n value: is_multiple value: 9 value: e.].

	[input atEnd]whileFalse:[
		|i c line stream|
		line := input nextLine.
		stream := generate value.
		1 to: line size do:[:index|
			c := (line at: index) asString.
			stream := (f at: c) value: stream.
		].
		i:=0.
		[i<10]whileTrue:[
			(i>0)ifTrue:[',' displayOn: stdout.].
			stream next displayOn: stdout.
			i:=i+1.
		].
		Character nl displayOn: stdout.
		stdout flush.
	].
].
main value: stdin.
```