.NETのYieldが何をしているか

.NETのYieldがどんなふうにILを出力してるんか調べてみた
VBだけ調べたけどC#も多分一緒だろう
割とcall/ccするのめんどいな

1. Yieldの付いた関数毎にIEnumeratorなクラスを作る、とりあえずStateMachineと呼ぶ
2. Yieldの付いた関数の引数、ローカル変数を全部メンバ変数に持つ
3. 戻り値と状態もメンバ変数に持つ
4. Yieldの出現箇所にユニークな連番を振る
5. Yieldしている個所の前で次のことをする
・Yieldの値を戻り値のメンバ変数に入れる
・4.で付けたユニークな番号を状態のメンバ変数に入れる
・Return Trueしとく
・Returnの後にユニークな番号に対応したラベルを張る
6. 関数を抜けるときに次のことをする
・最終行でっせというラベルを張る
・状態のメンバ変数に最終行でっせという値を入れる
・Return Falseする

' 呼び出し側
For Each x In Cdr(xs)
    ' なんか処理
Next

Public Shared Iterator Function Cdr(xs As List(Of Integer))
	For i = 1 To xs.Count - 1
		Yield xs(i)
	Next
End Function' 呼び出し側
For Each x In New StateMachine With {._xs = xs}
    ' なんか処理
Next

' Yieldの関数展開結果
Class StateMachine
	Implements IEnumerator

	Private _i As Integer
	Private _xs As List(Of Integer)
	
	Private _value As Integer
	Private _state_machine As Integer = 0
	
	Public ReadOnly Property Current() As Boolean
		Get
			Return _value
		End Get
	End Property
	
	Public Function MoveNext() As Boolean
		
		If _state_machine = 1 Then Goto __STATE1
		If _state_machine = 2 Then Goto __STATE2
		
		_i = 1
		Do While _i <= _xs.Count - 1
			
			_value = _xs(_i)
			_state_machine = 1
			Return True
			__STATE1:
			
			_i += 1
		Loop
		
		__STATE2:
		_state_machine = 2
		Return False
	End Function
End Class

簡単にcdrするILの関数書きたいだけなんだけど難しいなー・・・

クラッシュレポートを表示しない方法

Windowsでわざとクラッシュするプログラムを作ると報告ダイアログなんかがでてきてうっとうしかった
標準エラーにエラーはいてただ落ちればいいのに・・・


レジストリを設定すれば正しい動作に修正できるみたい
ついでにクラッシュダンプも作るのやめれるっぽい
これでセグメンテーションフォルト起こし放題だね!やったね!

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\Windows Error Reporting]
"DisableQueue"=dword:00000001
"ForceQueue"=dword:00000001

関数の戻り値型から空配列の型解決

なんのこっちゃか分かりにくいけど
戻り値の型から空配列の型解決ができるようになった
f:id:zenu:20170913204222p:plain

型解決をするために配列を正規化している

return([])
↓
$0 = []
return($0)

これをやると問題になるのがこんなやつ

xs = [Int]()
↓
$0 = [Int]
xs = $0()

Intってのが型解決してみるまで変数なのか型なのか分からないので$0が配列型か配列か分からない
ってゆーか、変数に型の代入ができなかった


Nodeにインスタンスか型なのかのフラグを付けて対応したけど、これができひんのは分かっている
どうしようもないので後で考える

var xs = []
xs.Add(Int)
var i = xs[0]()

ブラックジャックの点数

ブラックジャックの点数を数えるプログラムが思ってたのと全然違った
employment.en-japan.com

Aを2回以上11と数えるとバースト確実やねんから
Aの枚数=Aの合計値とみなしてかまへん

Aの枚数とA以外の合計値を求め、合計値-1が10以下ならA1枚を11とする
他はAを1と数えるだけでいい

せやないと6個のデッキをごちゃまぜにしてプレイしたときの
エース21枚という合法手に対し計算がややこしくなるやん(するかい、そんなん)

sumHand2 :: [Card] -> Int
sumHand2 cards | as == 0           = ax
               | ax + as - 1 <= 10 = ax + as - 1 + 11
               | otherwise         = ax + as
               where (a, xs) = partition (== A) cards
                     ax      = sum (map toPoint2 xs)
                     as      = length a

toPoint2 :: Card -> Int
toPoint2 A     = 1 -- 不要だけど書いておく
toPoint2 (N n) = n
toPoint2 _     = 10

そういえば練習でポーカーの手役を判定するプログラムと麻雀のシャンテン数を数えてたけど
作り途中でほっぽったのはどこ行ったんだろう
前のPCの中かな?

関数内型定義

関数内で型が定義できるようになった
インナー関数が作れたついでにやってみたらすぐできた
メソッド的なものは作るつもりはないので大体そろった感じ
f:id:zenu:20170903023907p:plain
次はなにつくろっかなー
例外関係かな

空気を読んだ関数のオーバーロード

関数の戻り値から関数のオーバーロードができるようになった
いゃったぁ!
こんな書き方しないけど!

f:id:zenu:20170902132721p:plain

今までインナー関数はマングリング(?)してグローバル関数として作っていたけど
returnを関数として実装している都合、関数毎にインナー関数用のスコープを持たせることにした

弟切草

叔父が亡くなって洋館を相続したので、彼氏と見学に行く
実は叔父が実の父で、なんか有名っぽい画家だったらしい
洋館を探索してるとミイラを見つけてしまい、逃げようとするけど車が倒木直撃し大破
管理人に襲われ、管理人室を見つけると監視カメラが全室に仕掛けられていた
管理人が彼女の妹(のような弟)で彼氏をクロスボウで射抜き、姉に父の絵を完成させるように迫る
絵が目を潰し炎に焼かれる絵なので、その通りにし館全焼


そこで終わってりゃいいものを、ゲームのプレイオチで、彼氏が助けて生き延びるシーンも見る


低予算を無理矢理誤魔化しました感が隠しきれてない
原作ゲームだからってそっちのオチに持ってくこと無いだろうに…