Hatena::ブログ(Diary)

匣の向こう側 - あまりに.NETな RSSフィード

2010-09-29(Wed)

[][]C#の型推論は怠けすぎ

C#のvarとtry〜catchが糞すぎる - やねうらお−ノーゲーム・ノーライフ(via やねうらおさんとこ)

C#はバランスと取れた良い言語ですが、あえて欠点を挙げると型推論がイマイチですよね。

using System;
using System.Collections.Generic;

module M
{
    static Main() : void 
    {
        // C#のvarに近いが初期化は必須ではない
        // mutable x = null;もOK。この場合、代入は参照型のみになる
        mutable x;

        try {
            // 適当なコード
            x = Dictionary.[int, string]();
            x[10] = "ten";
        }
        catch {
            | x is Exception => Console.WriteLine(x);
        }
        finally 
        {
            match (x)
            {
                | y is IDisposable => y.Dispose()
                | _ => ();
            }
        }
    }
}

C#2.0の頃のNemerleでもこの程度は推論してくれます。・・・と、久々にNemerleのコードを書いてみました。

2008-01-27(Sun)

[]中の人

Nemerleの開発者って今はMSの中の人なんだ。メーリングリスト読んで気づきました。(^^;

2007-08-28(Tue)

[][]久々に

Nemerleのsvnを覗いてみたら今月、0.9.4が出るような記述がありました。1年半ぶりでしょうか。(^^;

ほとんどが内部的なリファクタリングですが、新機能としてはC#3.0のAuto Propertyが実装されているみたいです。個人的にはmutableキーワードをvarにして、早く1.0をリリースして欲しいんだけどなぁ。

C#3.0で型推論が追加されましたが、varは代入時にしか使えないし、ラムダ式をvar変数に代入しようとするとエラーになるので、

using System;
using System.Linq;
using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class Program
    {
        static int Fibonacci(int n)
        {
            Func<int, int, int, int> fib = null;
            fib = (x, y, z) =>
            {
                if (x == 0) return y;
                return fib(x - 1, y + z, y);
            };
            return fib(n - 1, 1, 0);
        }
        static void Main()
        {
            Console.WriteLine(Fibonacci(10));
        }
    }
}

こんな記述をしなければなりません。ところで上記で使っているようなdelegate変数を宣言しておくことで再帰呼び出し可能にするテクニック(?)が逃げ道っぽくて気になります。

            var fib = (x, y, z) =>
            {
                if (x == 0) return y;
                return fib(x - 1, y + z, y);
            };
            return fib(n - 1, 1, 0);

こう書けて欲しいのですが・・・

Nemerleだと型推論が強力なのでもーちょっと頑張るし、そもそもローカル関数をサポートするので再帰呼び出しのための小細工は不要だったりします。

using System;

module Program 
{
    Fibonacci (n : int) : int
    {
#if true
        mutable fib;
        fib = (x, y, z) =>
        {
            | (0, _, _) => y
            | _ => fib(x - 1, y + z, y)
        }
#else
        // Nemerleは普通にローカル関数を書けるがC#との対比のため
        def fib (x, y, z)
        {
            | (0, _, _) => y
            | _ => fib(x - 1, y + z, y)
        }
#endif
        fib (n - 1, 1, 0)
    }

    Main() : void
    {
        Console.WriteLine (Fibonacci(10));
    }
}

2006-12-04(Mon)

[]NemerleUnit

The resource cannot be found.

単体テスト用の構文(?)がサポートされた模様。公式サイトの更新も久々ですね。メーリングリストは活発なのですが、VS用プラグインやら、マクロの実装周りの話ばかりで中々ネタにできません。(^^;

2006-07-13(Thu)

[]mutable vs var

公式フォーラムの方で再び議論になっています。流れを見ていると今回はあっさりvarが通りそうな雰囲気・・・

Nemerleの中の人もこんなマクロをアップして、これをデフォルトに入れるべきかどうかが問題だ。とか言っていますが、ユーザは皆Goサインを出しています。(^^;

using Nemerle.Compiler;

macro @var (body) 
syntax ("var", body) 
{ 
  match (body) { 
    | <[ $(nm : name) ]> => <[ mutable $(nm : name); ]> 
    | <[ $(id : name) = $init ]> => <[ mutable $(id : name) = $init; ]> 
    | <[ $name = $init ]> => <[ mutable $name = $init; ]> 
    | _ => Message.FatalError ($"incorrect variable definition '$body'"); 
  } 
}

↑ちなみにこれは、varキーワードを有効にするマクロです。

2006-07-08(Sat)

[]Late Binding Macro

メーリングリストを見ていたら、Late Bindingを行うマクロが投稿されていました。面白そうなので、Booサイトにあったduck typingのサンプルを移植してみました。

using System;
using System.Threading;
using Kitsu.LateBinding;

def CreateInstance (progID : string) {
    def t = Type.GetTypeFromProgID (progID);
    Activator.CreateInstance (t);
}

def ie = CreateInstance ("InternetExplorer.Application");
late {
    ie.Visible = true;
    ie.Navigate2 ("http://nemerle.org/");
    while (ie.Busy:>bool) Thread.Sleep (500);

    def doc = ie.Document;
    Console.WriteLine ("{0} is {1} bytes long.", doc.title, doc.fileSize);
}

変数ieの型はObjectなのに、メソッドやプロパティにアクセスしています。仕掛けはlateブロックで、この中ではLate Binding、つまり、Reflectionを使ったInvoke〜に変換されるのでした。

COM呼び出しなどの場合、便利そうですね。マクロの詳細についてはこちらを見てください。

2006-06-11(Sun)

[][]Decimalの数値計算

System.Mathには無かったので自前でちまちま。

using System;

def abs (x) {
    if (x < 0.0m)
        -x
    else
        x
}

def log (x) {
    if (x <= 0.0m) {
        0.0m;
    }
    else {
        def N=9;
        mutable a = x - 1;
        mutable s = 0.0m;
        for (mutable i = N; i >= 1; --i)
            s = i * a / (2 + i * a/ (2 * i + 1 + s));
        a / (1 + s);
    }
}

def exp (x) {
    def eps = 0.00000000000000000001m; // 1.0E-20までの誤差を見る
    mutable flag = true;
    mutable a = abs (x);
    mutable s  = 1.0m;
    mutable e  = 1.0m;
    mutable d  = 1.0m;
    mutable i  = 1.0m;

    while (flag) {
        d = s;
        e = e * a / i;
        s = s + e;
        when (abs (s -d) < eps * abs (d)) {
            when (x < 0.0m)
                s = 1.0m / s;
            flag = false;
        }
        ++i;
    }
    s;
}

def n = 100000000.0m;
Console.WriteLine (exp ((n-2.0m) * log(1.0m - 1.0m / n)));

/* 結果
0.367879446689634005080244756
 */

数学に全然自信がないので、数値計算はおっかなびっくりです。(^^;