LoginSignup
1

More than 5 years have passed since last update.

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マクロによって,定義されるので,new~Dispose()パターンみたいな,たくさん使われるパターンに使うと見やすくなり,コードの行数も減ります.

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

Basic時代はよくつかわれていたGoto文ですが,NemerleでもNemerle.Imperative.GoToをusingすることで使えます.(ただ,使いたくなったときは,関数を分けた方がいいと思います.)

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

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