1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2017-09-10

はじめに

Nemerleのgit探っていって,使い方がわかったものをのせていきます.わかったらどんどん追記していくかもしれません.

どうでもいい人はⅧへゴー!
Ⅷへ

匿名型

生成

Nemerle.Extensionsをusingすることで使えます.C#とは少し違います.

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

Tupleからの変換

NemerleのTupleから変換することができます.ただし,System.TupleSystem.ValueTupleからは変換できません.

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

sizeof

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

メモ化再帰(動的計画法)

関数の引数と戻り値を記憶してくれて,2回目以降呼び出されるときは,その値を返すので,オーダーが減ります.(Nemerle使えるコンテストはSphere Online Judgeぐらいですが)

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

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

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文です.これは,関数の中で書かなければなりません.

surroundwith
surroundwith(surround1, surround2, ...) {
  // ...
}

実際に使ってみると,以下のようになります.(usingは省いてます)

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

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

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

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

他にも,例を出しておきます.

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

記号ではない論理演算子

論理演算子&|!を英語で書けるマクロです.

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において,ラベルはマクロでの実装となります.そのため,複数の処理を記述するには,ブロックが必要となります.

label
test:{
  test();
}

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

書き方2

goto文のように書きたい場合では,NemerleでもNemerle.Imperative.GoTousingすることで使えます.

label_and_goto
using Nemerle.Imperative.GoTo;
goto hoge;    // hogeラベルにジャンプ!
label hoge;   // hogeラベル
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?