Hatena::ブログ(Diary)

NyaRuRuの日記 RSSフィード

archive

2007-08-02

徒然 C#

C# は Ruby よりも Python に近づいている

http://www.kt.rim.or.jp/~kbk/zakkicho/07/zakkicho0708a.html#D20070801-3 経由.

余談だが、1つだけ補足しておこう。ここでRubyを説明の例に出したのは、 Rubyが優秀な言語であり、C#は努力によってRubyに近づくことができる…… という主張を行うためではない。Rubyは面白い言語ではあるが、本来の能力から見ると、 最近の社会的な評価は過剰に高すぎるという印象がある。逆に、 C#は本来の能力から見ると、社会的な評価が過剰に低すぎる感がある。 筆者の漠然とした印象からいえば、個別の機能ではなく総合力で見れば RubyよりもC# 2.0の方がはるかに強力であり、実用性は高いと感じる。

第3回 新しい繰り返しのスタイル − yield return文とForEachメソッド − @IT

まあ色々な視点があると思うのですが,C# で言うところの IEnumerable<T> を議論の中心に据えた場合,そこで比較の相手に持ってくるべきは Ruby じゃなくて Python だと思うのですよ.偉大なる Pythonista が何年もかけて錬成した generator の Best Practice には,C# 2.0 以降で参考になる話がいっぱい含まれているんじゃないかと.ってまあ @IT の記事中には LINQ という言葉は一文字も出てこないあたり,そんなことを突っ込むには位相が 2 年ぐらいズレているようですが.

という話を Python 3000 FAQ の訳を拝読しながら思ったり.

濫用と有用性

C# 3.0 における「Lambda の濫用」,「過度に関数型プログラミングを意識したスタイル」の見本市みたいな日記を書き散らかしている私がこんなことを言うのもなんですが,実際問題こんなコード書くぐらいなら素直に yield で書けと言い切れる Python の世界認識は正しいと思います.

Func<int, int> fact =
    N => {
        var seq = Enumerable.Concat
            (
                Enumerable.Repeat(1, 1), // fact(0)
                Enumerable.Range(1, N)
            );
        return seq.Aggregate( (ret, n) => n * ret );
    };

Python にあって C# に決定的に欠けているものと言えば,C# では入れ子になった関数で yield を使えないということでしょうか.これさえできれば,C# で Aggregate を駆使しなければならない理由も,一発芸以外の目的で C# に unfold を持ち込む理由も,まず無くなると思っています.

def printfib(n):
    import itertools
    def innerfib():
        (first, second) = (1,1)
        while 1:
            yield first
            (first, second) = (second, first+second)
    for i in itertools.islice(innerfib(), n):
        print i

せっかくなので IronPython 2.0 alpha 3 で書いてみました.LINQ マニアは IterTools.cs はいっぺん読んでおくと吉.

どうしても C# に unfold を持ち込みたくなるとすれば,クエリを実行時に最適化したいという場合でしょうか.yield return を使ってしまうと,Expression Tree に展開できなくなります.式をまるまる受け取りたければ,unfold を導入して,いかにも関数型っぽい Expression Tree を作ることになるんじゃないかと思います.

SQL-like syntax

var f1 = from x in Enumerable.Range(1, 100) let a = x % 3 == 0 ? "Fizz" : "" let b = x % 5 == 0 ? "Buzz" : "" let c = (x % 3 != 0 && x % 5 != 0) ? x.ToString() : "" select a + b + c;

var f2 = from x in Enumerable.Range(1, 100)
         let a = x % 3 == 0 ? "Fizz" : ""
         let b = x % 5 == 0 ? "Buzz" : ""
         let c = (x % 3 != 0 && x % 5 != 0) ? x.ToString() : ""
         select a + b + c;

この 2 つが同じ式であるというのは改めてみるとビックリですが,C# 3.0 はこういう文法です.

中括弧が減ると,ソースコードの見た目がずいぶんと変わるのが実感できますが,その先に何が起きるかはまだよく分かりません.まあこのゲームにオフサイドがないことは確かです.

そして Yokohama へ

せっかく波村さんが来日されることですし,TechEd に向けて積もった話を暖めておきましょうか.って 5 ヶ月前にお世話になったばっかりですが.

関連エントリ

siokoshousiokoshou 2007/08/05 00:24 Aggregateは確かにわかりづらいなぁと思いますが、unfoldは漸化式をほぼ素直に書けるのでわかりやすいような気がします。ただ、名前は再考の余地ありと思いますが(^^;

NyaRuRuNyaRuRu 2007/08/05 01:28 末尾再帰の扱いを気にするより,unfold で定式化する方が色々安心感はあるんですよねぇ.
個人的には,unfold は大好きで,それでいて「自重しろ」と言ってくれる Python も好感が持てて,なかなか難しいところですな.
まあとりあえず let ですよ.let 使いましょうぜ.

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証