拡張メソッド

C#3.0のアレ。Nemerleでもサポートされました。

using System;

module Extentions {
    public ToInt32 (this s : string) : int {
        Int32.Parse (s)
    }
}

def s = "123";
Console.WriteLine ("s = {0}", s.ToInt32 ());

構文はC#3.0同様、引数の前にthisを付けるようです。あと、Nullableもサポートされた見たいですが、使い方が分からない(コンパイルエラーになる)のでサンプル待ちです。(^^;


ちなみにNemerleにおけるC#3.0相当機能の実装状況は、

LINQ
Monoの人がオープンソースSystem.Query.dllをこさえて、macroを作成中らしい。
型推論
実装済み。C#3.0より強力。
拡張メソッド
実装済み。
ラムダ式
実装済み。
イニシャライザ
未実装。
匿名型
未実装。
暗黙型付け配列
型推論に含まれる。

mixin in Nemerle

Nemerle 0.9.2からProxyPublicMembersマクロがサポートされました。この属性を付けると、オブジェクトの持つpublicなメンバへの委譲が自動生成されます。

using System;
using Nemerle.Utility;
using Nemerle.DesignPatterns;

class Programmer {
    [Accessor]
    lang : string;
    this (lang : string) {
        this.lang = lang;
    }

    public static Create (lang : string) : Programmer {
        Programmer (lang);
    }

    public WriteCode () : void {
        Console.WriteLine ($"Programming in $lang");
    }

}

class Singer {
    this () {}

    public static Create () : Singer {
        Singer ();
    }

    public Sing () : void {
        Console.WriteLine ("Sing a song.");
    }
}

class Dancer {
    this () {}

    public static Create () : Dancer {
        Dancer ();
    }

    public Dance () : void {
        Console.WriteLine ("Dance to the music.");
    }
}

class SuperProgrammer {
    [ProxyPublicMembers]
    programmer : Programmer;

    [ProxyPublicMembers]
    singer : Singer;

    [ProxyPublicMembers]
    dancer : Dancer;

    public this (lang : string) {
        programmer = Programmer.Create (lang);
        singer = Singer.Create ();
        dancer = Dancer.Create ();
    }
}

// 歌って踊れるプログラマ
def hacker = SuperProgrammer ("C#");
Console.WriteLine (hacker.Lang);
hacker.WriteCode ();
hacker.Sing ();
hacker.Dance ();

/*
C#
Programming in C#
Sing a song.
Dance to the music.
 */

ただ、現在のマクロはpublicなコンストラクタまで委譲してしまい、コンストラクタが重複してしまいます。取りあえず、Creation Methodを作って逃げました。

Adapterパターン

Nemerleの特徴を利用して変則的に実装してみました。

using Nemerle.Utility;

// 移譲先
public class Banner {
    text : string;

    public this (text : string) {
        this.text = text;
    }
    public ShowWithParen () : void {
        System.Console.WriteLine ($"($text)");
    }
    public ShowWithAster () : void {
        System.Console.WriteLine ($"*$text*");
    }
}

// アダプタのインタフェース
public interface IPrint {
    // 関数型(≒C#delegate)のプロパティを持つ
    // void -> void は 引数void、戻り値voidの関数を意味する 
    PrintWeak : void -> void { get; }
    PrintStrong : void -> void { get; }
}

public class Print : IPrint {
    banner : Banner;
    [Accessor]
    printWeak : void -> void;
    [Accessor]
    printStrong : void -> void;

    public this (text : string) {
        // Bannerクラスへ委譲
        banner = Banner (text);
        printWeak = banner.ShowWithParen;
        printStrong = banner.ShowWithAster;
    }
}

def print = Print ("Hello");

print.PrintWeak ();
print.PrintStrong ();

/* 結果
 (Hello)
 *Hello*
 */

quick sort

List comprehensionsがサポートされたのでクイックソートを書いてみる。

def sort (l : list [int]) {
    |  => 
    | x::xs => sort($[y | y in xs, y < x]) + [x] + sort ($[y | y in xs, y > x]) 
}

def lst = [9, 1, 2, 8, 3, 7, 4, 6, 5, 0];
System.Console.WriteLine (sort (lst));

Haskell版とほとんど一緒ですね。ただ、個人的にはList comprehensionsの$が好みじゃないです。

Ranges

List comprehensions内で...を使って範囲指定が出来るようになったみたい。

[ 開始 ... 終了]

または、

[開始, 次の値 ... 終了]

こちらだと、次の値-開始がステップ値になります。ってコード見た方が早いですね。

using System;

Console.WriteLine ($[ x | x in [1 ... 10] ]);
Console.WriteLine ($[ x | x in [1, 3 ... 10] ]);
Console.WriteLine ($[ x | x in [10, 9 ... 1] ]);
Console.WriteLine ($[ x | x in [10, 8 ... 1] ]);
Console.WriteLine ($[ (x, y) | x in [1 ... 3], y in [2 ... 4], x < y]);

/*
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 3, 5, 7, 9]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[10, 8, 6, 4, 2]
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
 */

yieldその後

結構、使えるようになってきた?

using System;
using System.Collections.Generic;

class Fib : IEnumerable [int] {
    mutable max = 0;
    public this (n : int) {
        max = n;
    }

    public GetEnumerator () : IEnumerator [int] {
        mutable (a, b) = (0, 1);
        while (b < max) {
            yield b;
            (a, b) = (b, a + b);
        }
    }
}

foreach (n in Fib (20))
    Console.WriteLine (n);

/*
1
1
2
3
5
8
13
 */