Nemerle入門Ⅶ ～もっとマクロ紹介～

# はじめに
Nemerleのgit探っていって，使い方がわかったものをのせていきます．わかったらどんどん追記していくかもしれません．

どうでもいい人はⅧへゴー！
[Ⅷへ](http://qiita.com/Gnico/items/25735e41e21f7ce4098a)

# 匿名型
## 生成
`Nemerle.Extensions`をusingすることで使えます．C#とは少し違います．

```nemerle:AnnonymousClass
using Nemerle.Extensions;
def fuga = new (Size = 1, Name = "string");
```

## Tupleからの変換
NemerleのTupleから変換することができます．ただし，`System.Tuple`や`System.ValueTuple`からは変換できません．

```nemerle:AnnonymousClass_ConvertFrom_Tuple
def t = (12, "string");
def fuga = new[Size,Name](t); 
```

# sizeof
Nemerleでは`sizeof`がマクロとして定義されています．それだけのことです．（使い方はC#と同じです）

# メモ化再帰（動的計画法）
関数の引数と戻り値を記憶してくれて，2回目以降呼び出されるときは，その値を返すので，オーダーが減ります．（Nemerle使えるコンテストはSphere Online Judgeぐらいですが）

```nemerle:memoize
[Memoize]
fib(long n) : long {
  | 0
  | 1 => n
  | _ => fib(n - 1) + fib(n - 2)
}

// 展開された疑似コード
mutable _fib_hash = Nemerle.Collections.Hashtable.[long, (long * bool)];
fib(long n) : long {
  def Memo : Nemerle.Builtins.Tuple = _fib_hash.TryGetValue(n);
  if(Memo[1]) return Memo[0];
  else {
    // 元のfib関数の本体
    def result = match(n) {
                    | 0
                    | 1 => n
                    | _ => fib(n - 1) + fib(n - 2)
                 };
    _fib_hash[n] = result;
    return result;
  }
}
//(fib関数がstaticなら，_fib_hashにもstaticがつくはず)
```

# SurroundWith
`surroundwith`は`using`みたく，囲まれたブロックの前後の処理を挿入してくれます．使うには，`Nemerle.Surround`をusingする必要があります．
そして，その処理は，`DefineSurround`マクロによって，定義されるので，`new`～`Dispose()`パターンみたいな，たくさん使われるパターンに使うと見やすくなり，コードの行数も減ります．

```nemerle:definesurround
using Nemerle.Surround;
[assembly: DefineSurround("SurroundName", false, WriteLine("START"), WriteLine("END"))]

//各引数の引数名は以下の通り
DefineSurround(SurroundName : string, UseTryFinally : bool, BeforeExpr : PExpr, AfterExpr : PExpr)

```

まず，`DefineSurround`によって，挿入する処理を定義します．このマクロは，プロジェクトのどの部分に書いてもよいです．各引数の意味は以下の通りです．

> **SurroundName** Surroundの定義名．surroundwith構文でどのSurroundを使うかを指定するために定義します．
 **UseTryFinally** try{}finally{}パターンにするか．trueが渡されると，`try{ BeforeExpr;ContentExpr; }finally{ AfterExpr }` という形に展開されます．
 **BeforeExpr** 前に挿入されるコード
 **AfterExpr** 後ろに挿入されるコード

そして，次に，`surroundwith`文です．これは，関数の中で書かなければなりません．

```nemerle:surroundwith
surroundwith(surround1, surround2, ...) {
  // ...
}
```

実際に使ってみると，以下のようになります．（usingは省いてます）

```nemerle:surround1
[assembly: DefineSurround("TextRead", true, {def stream = StreamReader("hoge.txt");}, stream.Dispose()]

module fuga {
  Main() : void {
    surroundwith(TextRead) {
      while(!stream.EndOfStream){ 
        // do something...
      }
    }
  }
}
```

上のように書いた場合，以下のように展開されます．

```nemerle:surround2
Main() : void {
  try {
    def stream = StreamReader("hoge.txt");
    while(!stream.EndOfStream) {
      // do something...
    }
  } finally {
    stream.Dispose()
  }
}
```

他にも，例を出しておきます．

```nemerle:surround3
using System.Console;
using Nemerle.Surround;

[assembly: DefineSurround("surround1", false, WriteLine("Surround1Before"), WriteLine("Surround1After"))]
[assembly: DefineSurround("surround2", false, WriteLine("Surround2Before"), WriteLine("Surround2After"))]
[assembly: DefineSurround("surround3", false, WriteLine("Surround3Before"), WriteLine("Surround3After"))]

module Test
{
  Main() : void
  {
    surroundwith (surround1, surround2, surround3)
      WriteLine("Test1");

    WriteLine();

    surroundwith (surround1)
      WriteLine("Test2");

    WriteLine();

      surroundwith (surround1)
    surroundwith (surround2)
      WriteLine("Test3");

  }
}
```

この場合，出力は，以下のようになります．

```
Surround1Before
Surround2Before
Surround3Before
Test1
Surround3After
Surround2After
Surround1After

Surround1Before
Test2
Surround1After

Surround1Before
Surround2Before
Test3
Surround2After
Surround1After
```

# 記号ではない論理演算子
論理演算子`&|!`を英語で書けるマクロです．

```nemerle:English_LogicalOperation
using Nemerle.English;
def b1 = true, b2 = false;
@and(b1, b2)
   // は b1 && b2 とおなじ
@or(b1, b2)
   // は b1 || b2 とおなじ
@not(b1)
   // は !b1 とおなじ
```

# ラベルとGoto
## 書き方1
Nemerleにおいて，ラベルはマクロでの実装となります．そのため，複数の処理を記述するには，ブロックが必要となります．

```nemerle:label
test:{
  test();
}
```

`:`をつけることにより，ラベルに，関数と同じように呼ぶと，その場所に戻ります．
返し値を付ける場合は，`()`の中に値を指定すれば良いです．

## 書き方2
`goto`文のように書きたい場合では，Nemerleでも`Nemerle.Imperative.GoTo`を`using`することで使えます．

```nemerle:label_and_goto
using Nemerle.Imperative.GoTo;
goto hoge;    // hogeラベルにジャンプ！
label hoge;   // hogeラベル
```