はじめに
Nemerleのgit探っていって,使い方がわかったものをのせていきます.わかったらどんどん追記していくかもしれません.
どうでもいい人はⅧへゴー!
Ⅷへ
匿名型
生成
Nemerle.Extensions
をusingすることで使えます.C#とは少し違います.
using Nemerle.Extensions;
def fuga = new (Size = 1, Name = "string");
Tupleからの変換
NemerleのTupleから変換することができます.ただし,System.Tuple
やSystem.ValueTuple
からは変換できません.
def t = (12, "string");
def fuga = new[Size,Name](t);
sizeof
Nemerleではsizeof
がマクロとして定義されています.それだけのことです.(使い方はC#と同じです)
メモ化再帰(動的計画法)
関数の引数と戻り値を記憶してくれて,2回目以降呼び出されるときは,その値を返すので,オーダーが減ります.(Nemerle使えるコンテストはSphere Online Judgeぐらいですが)
[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()
パターンみたいな,たくさん使われるパターンに使うと見やすくなり,コードの行数も減ります.
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
文です.これは,関数の中で書かなければなりません.
surroundwith(surround1, surround2, ...) {
// ...
}
実際に使ってみると,以下のようになります.(usingは省いてます)
[assembly: DefineSurround("TextRead", true, {def stream = StreamReader("hoge.txt");}, stream.Dispose()]
module fuga {
Main() : void {
surroundwith(TextRead) {
while(!stream.EndOfStream){
// do something...
}
}
}
}
上のように書いた場合,以下のように展開されます.
Main() : void {
try {
def stream = StreamReader("hoge.txt");
while(!stream.EndOfStream) {
// do something...
}
} finally {
stream.Dispose()
}
}
他にも,例を出しておきます.
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
記号ではない論理演算子
論理演算子&|!
を英語で書けるマクロです.
using Nemerle.English;
def b1 = true, b2 = false;
@and(b1, b2)
// は b1 && b2 とおなじ
@or(b1, b2)
// は b1 || b2 とおなじ
@not(b1)
// は !b1 とおなじ
ラベルとGoto
書き方1
Nemerleにおいて,ラベルはマクロでの実装となります.そのため,複数の処理を記述するには,ブロックが必要となります.
test:{
test();
}
:
をつけることにより,ラベルに,関数と同じように呼ぶと,その場所に戻ります.
返し値を付ける場合は,()
の中に値を指定すれば良いです.
書き方2
goto
文のように書きたい場合では,NemerleでもNemerle.Imperative.GoTo
をusing
することで使えます.
using Nemerle.Imperative.GoTo;
goto hoge; // hogeラベルにジャンプ!
label hoge; // hogeラベル