型推論の落とし穴
Nemerleの型推論は基本的にC#3.0より強力ですが、Nemerleがタプルをサポートしていることが仇になってLINQライブラリの推論を失敗するケースがあります。
次の例の1つめはIEnumerable<T>と関数(引数がT、戻り値がS)を引数に取って、IEnumerable<S>に変換するメソッドです。2つめは、関数の引数が2つ(Tとint)で戻り値がSになっています。
using System; using System.Collections.Generic; using Nemerle.IO; public module M { public F [T,S] (this objs : IEnumerable [T], fn : T -> S) : IEnumerable [S] { foreach (t in objs) yield fn (t); } public F [T,S] (this objs : IEnumerable [T], fn : T * int -> S) : IEnumerable [S] { mutable i = 0; foreach (t in objs) { yield fn (t, i); ++i; } } } def ls = $ [0 .. 10]; foreach (s in ls.F (x => x)) printf("%s\n", s); /* b.n:21:15:21:19: [01;31merror[0m: typing fails on ambiguity between overloads: method M.F(objs : System.Collections.Generic.IEnumerable[T.722], fn : T.722 -> S.723) : System.Collections.Generic.IEnumerable[S.723] method M.F(objs : System.Collections.Generic.IEnumerable[T.724], fn : (T.724 * int) -> S.725) : System.Collections.Generic.IEnumerable[S.725] */
コンパイル結果は、型推論に失敗してコンパイルエラーになります。しかし、渡している関数は、
x => x
このように引数を一つだけ取るので最初のメソッドを推論出来そうなものです。ところが、Nemerleの場合、タプルをサポートしているので、上記のxが(x,y)のような2つの組ということも考えられます。つまり、引数が1つなのか、2つの値の組を持つ1つのタプルなのか決めかねるので推論が出来ません。
これはLINQを使うときにネックになりそうな気がするので、何か上手い解決方法が欲しいところです。