C#の型推論は怠けすぎ
2010-09-29(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() | _ => (); } } } }
久々に
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)); } }
NemerleUnit
・http://nemerle.org/NemerleUnit
単体テスト用の構文(?)がサポートされた模様。公式サイトの更新も久々ですね。メーリングリストは活発なのですが、VS用プラグインやら、マクロの実装周りの話ばかりで中々ネタにできません。(^^;
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キーワードを有効にするマクロです。
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呼び出しなどの場合、便利そうですね。マクロの詳細についてはこちらを見てください。
Decimalの数値計算
System.Mathには無かったので自前でちまちま。
続きを読む