カリー化 続々

クロージャを実装できた
関数外の変数に手を出している関数をマークして
関数外の変数を一個のframeにまとめる

var a = 1
var b = 2
sub f(c: Int)
    print(a + b + c)
f(3)

↑これを↓こう変換する

var a = 1
var b = 2
sub f_(frame, c: Int)
    print(frame.a + frame.b + c)

var frame # この辺が変換部分
frame.a = a
frame.b = b
f = f_.bind(frame)

f(3)

CILに変換するときは前回の部分適用でなんとかする
今のつくりはクロージャがネストすると1関数1frameで作っているので、どんどん引数が増える
まぁいっか

f:id:zenu:20160224232120p:plain

ILは笑っちゃうほど長い

//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.6.81.0
//  Copyright (c) Microsoft Corporation. All rights reserved.



// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly Global
{
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module Global
// MVID: {3B864071-7E41-437A-9EDF-B63D9808492F}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x00CA0000


// ================== GLOBAL METHODS =========================

.method public static class [mscorlib]System.Action`1<int32> 
        f1(int32 A_0) cil managed
{
  // コード サイズ       38 (0x26)
  .maxstack  2
  .locals init (class '##f1' V_0,
           class [mscorlib]System.Action`1<int32> V_1)
  IL_0000:  newobj     instance void '##f1'::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ldarg.0
  IL_0008:  stfld      int32 '##f1'::w
  IL_000d:  ldloc.0
  IL_000e:  ldc.i4.5
  IL_000f:  stfld      int32 '##f1'::z
  IL_0014:  ldloc.0
  IL_0015:  ldc.i4     0x14
  IL_001a:  nop
  IL_001b:  nop
  IL_001c:  nop
  IL_001d:  nop
  IL_001e:  call       class [mscorlib]System.Action`1<int32> f2(class '##f1',
                                                                 int32)
  IL_0023:  stloc.1
  IL_0024:  ldloc.1
  IL_0025:  ret
} // end of global method f1

.method public static class [mscorlib]System.Action`1<int32> 
        f2(class '##f1' A_0,
           int32 A_1) cil managed
{
  // コード サイズ       70 (0x46)
  .maxstack  3
  .locals init (class '##f2' V_0,
           class [mscorlib]System.Action`1<int32> V_1)
  IL_0000:  newobj     instance void '##f2'::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ldarg.1
  IL_0008:  stfld      int32 '##f2'::x
  IL_000d:  ldloc.0
  IL_000e:  ldloc.0
  IL_000f:  ldfld      int32 '##f2'::x
  IL_0014:  stfld      int32 '##f2'::y
  IL_0019:  newobj     instance void Bind_f3::.ctor()
  IL_001e:  stloc.1
  IL_001f:  ldloc.1
  IL_0020:  ldftn      void f3(class '##f1',
                               class '##f2',
                               int32)
  IL_0026:  stfld      native int Bind_f3::f
  IL_002b:  ldloc.1
  IL_002c:  ldarg.0
  IL_002d:  stfld      class '##f1' Bind_f3::'##f1'
  IL_0032:  ldloc.1
  IL_0033:  ldloc.0
  IL_0034:  stfld      class '##f2' Bind_f3::'##f2'
  IL_0039:  ldloc.1
  IL_003a:  ldftn      instance void Bind_f3::Invoke(int32)
  IL_0040:  newobj     instance void class [mscorlib]System.Action`1<int32>::.ctor(object,
                                                                                   native int)
  IL_0045:  ret
} // end of global method f2

.method public static void  f3(class '##f1' A_0,
                               class '##f2' A_1,
                               int32 A_2) cil managed
{
  // コード サイズ       65 (0x41)
  .maxstack  2
  .locals init (int32 V_0,
           int32 V_1,
           int32 V_2,
           int32 V_3,
           int32 V_4)
  IL_0000:  ldc.i4     0xa
  IL_0005:  nop
  IL_0006:  nop
  IL_0007:  nop
  IL_0008:  nop
  IL_0009:  ldarg.1
  IL_000a:  ldfld      int32 '##f2'::x
  IL_000f:  add
  IL_0010:  stloc.0
  IL_0011:  ldloc.0
  IL_0012:  ldarg.1
  IL_0013:  ldfld      int32 '##f2'::y
  IL_0018:  add
  IL_0019:  stloc.1
  IL_001a:  ldloc.1
  IL_001b:  ldarg.0
  IL_001c:  ldfld      int32 '##f1'::z
  IL_0021:  add
  IL_0022:  stloc.2
  IL_0023:  ldloc.2
  IL_0024:  ldarg.0
  IL_0025:  ldfld      int32 '##f1'::w
  IL_002a:  add
  IL_002b:  stloc.3
  IL_002c:  ldloc.3
  IL_002d:  ldarg.2
  IL_002e:  add
  IL_002f:  stloc      V_4
  IL_0033:  nop
  IL_0034:  nop
  IL_0035:  ldloc      V_4
  IL_0039:  nop
  IL_003a:  nop
  IL_003b:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0040:  ret
} // end of global method f3

.method public static void  '###.ctor'() cil managed
{
  // コード サイズ       15 (0xf)
  .maxstack  2
  .locals init (class [mscorlib]System.Action`1<int32> V_0)
  IL_0000:  ldc.i4.1
  IL_0001:  call       class [mscorlib]System.Action`1<int32> f1(int32)
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.2
  IL_0009:  callvirt   instance void class [mscorlib]System.Action`1<int32>::Invoke(!0)
  IL_000e:  ret
} // end of global method '###.ctor'

.method family static void  __EntryPoint() cil managed
{
  .entrypoint
  // コード サイズ       6 (0x6)
  .maxstack  0
  IL_0000:  call       void '###.ctor'()
  IL_0005:  ret
} // end of global method __EntryPoint


// =============================================================


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi '##f1'
       extends [mscorlib]System.Object
{
  .field public int32 w
  .field public int32 z
  .method public specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // コード サイズ       1 (0x1)
    .maxstack  0
    IL_0000:  ret
  } // end of method '##f1'::.ctor

} // end of class '##f1'

.class private auto ansi '##f2'
       extends [mscorlib]System.Object
{
  .field public int32 x
  .field public int32 y
  .method public specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // コード サイズ       1 (0x1)
    .maxstack  0
    IL_0000:  ret
  } // end of method '##f2'::.ctor

} // end of class '##f2'

.class private auto ansi Bind_f3
       extends [mscorlib]System.Object
{
  .field public native int f
  .field public class '##f1' '##f1'
  .field public class '##f2' '##f2'
  .method public specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // コード サイズ       7 (0x7)
    .maxstack  2
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Bind_f3::.ctor

  .method public instance void  Invoke(int32 A_1) cil managed
  {
    // コード サイズ       30 (0x1e)
    .maxstack  4
    IL_0000:  ldarg.0
    IL_0001:  ldfld      class '##f1' Bind_f3::'##f1'
    IL_0006:  ldarg.0
    IL_0007:  ldfld      class '##f2' Bind_f3::'##f2'
    IL_000c:  ldarg      A_1
    IL_0010:  nop
    IL_0011:  nop
    IL_0012:  ldarg.0
    IL_0013:  ldfld      native int Bind_f3::f
    IL_0018:  calli      void(class '##f1',class '##f2',int32)
    IL_001d:  ret
  } // end of method Bind_f3::Invoke

} // end of class Bind_f3


// =============================================================

// *********** 逆アセンブルが完了しました ***********************


ところで得正のカレーうどんはうまかった

f:id:zenu:20160220152357j:plain

カリー化 続き

上等カレーに行った
値段高いやろ、エビフライ乗ってるとはいえ1000円って…

ルーの味はまんま得正
得正には毎日通ってたのでまず間違いない
得正はカレーうどんなのでスープで多少割ってたかもしれないが、得正の常連であったもんがほぼ違いが感じられないレベル


得正のうどんと肉卵ライスよりさらに高いって…
ないわー
ホンマないわー
カレー専門店が1000円のカレー提供してんのと違うど
同じルーでサイコーにうまいカレーうどん出してるやないけ
うどんをゴハンに変えて値段1.5倍ってねぇ


書いてたら得正食べたくなった!
でももよりの肥後橋の得正はイマイチなんよなー
やっぱ4ビル店が安定やわー

関数のカリー化

CILでカリー化をする時のメモ
部分適用かな?まぁどっちでもいいや
クロージャをCILで実装するのに部分適用でやりたかったらメモ


例えばこんな感じの3引数の関数で先頭の引数をカリー化しちゃう
curryなんて関数があった場合

int32 f1(int32 a, int32 b, int32 c)
{
	return a + b + c;
}
bind = curry(f1, 1)
Console.WriteLine(bind(2, 3)) // => 6


引数の数に応じてカリー化を行うクラスを作っておく
関数と1個めの引数は呼び出し側でセットしてもらう

class Curry<T1, T2, T3, R>
{
	public native int f;
	public T1 var;
	
	int32 lambda(T2 x2, T3 x3)
	{
		calli self.f(self.var, x2, x3)
	}
}


呼び出し側はCurryのフィールドにセットしつつ
Funcに引き渡してあとはよしなにしてもらう
CILへの変換時に「bind = curry(f1, 1)」をこんな感じのコードにして
bindって引数にこれFuncでっせというフラグを付けておく
そのフラグ見てcallvirtする感じ

.assembly extern mscorlib
{
	.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
	.ver 4:0:0:0
}
.assembly Global
{
	.hash algorithm 0x00008004
	.ver 0:0:0:0
}

.method public static int32 f1(int32 a, int32 b, int32 c)
{
	// return a + b + c
	ldarg.0
	ldarg.1
	add
	
	ldarg.2
	add
	
	ret
}

.class public Curry<T1, T2, T3, R>
{
	.field public native int f
	.field public !T1 var
	
	.method instance void .ctor()
	{
		ret
	}
	
	.method instance !R lambda(!T2 x2, !T3 x3)
	{
		// self.f(self.var, x2, x3)
		ldarg.0
		ldfld !T1 class Curry<!T1, !T2, !T3, !R>::var
		
		ldarg.1
		ldarg.2
		
		ldarg.0
		ldfld native int class Curry<!T1, !T2, !T3, !R>::f
		
		calli !R (!T1, !T2, !T3)
		ret
	}
}

.method public static void __EntryPoint() cil managed
{
	.entrypoint
	.locals (
			class Curry<int32, int32, int32, int32> curry,
			class [mscorlib]System.Func`3<int32, int32, int32> bind
		)
	
	// Console.WriteLine(f1(1, 2, 3))
	ldc.i4.1
	ldc.i4.2
	ldc.i4.3
	call int32 f1(int32, int32, int32)
	call void [mscorlib]System.Console::WriteLine(int32)
	
	// bind = curry(f1, 1)
	// Console.WriteLine(bind(2, 3))
	
	// curry = new Curry<int32, int32, int32, int32>
	newobj instance void class Curry<int32, int32, int32, int32>::.ctor()
	stloc.0
	
	// curry.f = f1
	ldloc.0
	ldftn int32 f1(int32, int32, int32)
	stfld native int class Curry<int32, int32, int32, int32>::f
	
	// curry.var = 1
	ldloc.0
	ldc.i4.1
	stfld !0 class Curry<int32, int32, int32, int32>::var
	
	// bind = new Func<int32, int32, int32>(curry, curry.lambda)
	ldloc.0
	ldftn  instance !3 class Curry<int32, int32, int32, int32>::lambda(!1, !2)
	newobj instance void class [mscorlib]System.Func`3<int32, int32, int32>::.ctor(object, native int)
	stloc.1
	
	// Console.WriteLine(bind(2, 3))
	ldloc.1
	ldc.i4.2
	ldc.i4.3
	callvirt instance !2 class [mscorlib]System.Func`3<int32, int32, int32>::Invoke(!0, !1)
	call void [mscorlib]System.Console::WriteLine(int32)
	
	
	ldstr "end..."
	call void [mscorlib]System.Console::WriteLine(string)
	ret
}

関数の呼び出し方

関数はどうやって実行できるのか調べてみた
前にも調べたような気がするけど、忘れたのでもう一回


C#でInt->String->Intの関数を呼ぶ場合

delegate int F_dele(String s);
static int f(String s) {return(999);}
var x = new F_dele(f);
Console.Write(x("Hoge"));

C#様に任せると大体こうなる
staticな関数だとF_dele.ctorの第一引数はldnullらしい

ldnull
ldftn int32 f(string)
newobj instance void F_dele.ctor(object, native int)
stloc x

ldloc x
ldstr "Hoge"
callvirt instance int32 F_dele::Invoke(string)
call void Console::WriteLine(int32)


delegateはMulticastDelegateを継承したクラスになるが、正直よくわかんない
呼び出したい型ごとにクラス作って、ldftnした結果をいれるのはじゃんくさい
ldftnした結果の型を管理を自分でやるならこれで十分

ldftn int32 f(string)
stloc x

ldstr "Hoge"
ldloc x
calli int32 (string)
call void Console::WriteLine(int32)


C#でInt->String->Intのメソッドを呼ぶ場合

delegate int F_dele(String s);
virtual int f(String s) {return(999);}
var self = new Self();
var x = new F_dele(self.f);
Console.Write(x("Hoge"));

メソッドだとF_dele.ctorの第一引数はレシーバっぽい
virtualじゃないメソッドなら当然ldftnになる

newobj Self::.ctor
stloc self

ldloc self
ldvirtftn int32 f(string)
newobj instance void F_dele.ctor(object, native int)
stloc x

ldloc x
ldstr "Hoge"
callvirt instance int32 F_dele::Invoke(string)
call void Console::WriteLine(int32)


メソッドをldftnするとcalliの第一引数をレシーバにせんとならん
ってことはILに落とす前にこれは関数orメソッドだかんねと言う情報をもたせんとならん
ついでにメソッド高階関数にすんのがめんどい

そのせいかldftnをdelegateでラップして渡すのがC#様やVB様のやり方くさい
デリゲートなら定義するときにldftn/ldvirtftnを切り替えてレシーバ渡すだけになる
関数を呼ぶところはcallvirtに統一できる

ラムダ式の定義

こういう感じの「(x, y) => x」C#みたいなラムダ式を加えたら
reduce/reduce conflictでおま、と怒られた
ちゃんとreduce/reduceの判定できたんだ、このクソパーサジェネレータ・・・

LALR(k)にするには今更どーなおしたらいいもんか分からない
とりあえず文法を「{x, y} => x」ってゆーことにしてほっておこう

構造体が書けた

構造体が書けた
構造体そのものは簡単だったけど総称型を突っ込んだら内部構造色々変えないとうまくいかず面倒
f:id:zenu:20160126015015p:plain
こっちは当面ほっといて先にクロージャを実装しようかなぁ
とりあえずドラゴンクエストビルダーズが発売される前に一通りやっちゃわないとほっといて忘れそうな気がするので、困ったなぁ

前やってたこれが動けばとりあえずいいや

sub f(x: Int) #(=>Int)
    #return(f2)
    f2()
    sub f2()
        f3()
        sub f3()
            print(x)
#f1(1)()
f1(1)

ノード図はもうちょっとコンパクトにしたい
LetNodeとTypeNodeは文字列で書いちゃってもええかもしらん
f:id:zenu:20160126015024p:plain

EXPO CITY

EXPO CITYに行ってきた
ららぽーと?かなとりあえず地図の野球場感がハンパない

f:id:zenu:20160123172705j:plain

ライトスタンドあたりから入ってきて、1塁側に抜けてピッチャーマウンドまでまわり
外野をうろうろしてきた
3塁側はあんまし行ってない

狙ったんか、この形