100までの素数を求めるプログラム、その後(2)
どうも,もやもやしています.
前回は元ネタからif文とfor文を取り除き(if文は3項演算子に書き換え),関数言語風にしてみました.もちろんこんな実装だと,スタック消費が激しく,パフォーマンス的に使い物にならん,というのはありますが,そこはスルーの方向で.それよりは,本当に関数型言語的といえるのか?ってところがもやもや...
もちろんC#自身が純粋な関数型言語でないのは承知しているつもりです.この気持ちはちょうど,オブジェクト指向に出会ってすぐ,とりあえず継承を多用していたころに感じていたことと,なんとなく似ているような...(意味不明なたとえですみません)
前回のものをさらにいじってみます.
addListヘルパー関数(ラムダ式)は,List
internal static class MyExtensions { internal static List<T> AddAndReturn<T>(this List<T> v, T e) { v.Add(e); return v; } }
あとは,GetEnumerator()周りをいろいろいじって.PrimeListクラスは以下のようになりました.
internal class PrimeList : IEnumerable<int> { Func<List<int>, int, Func<List<int>, int, List<int>>, List<int>> rec = null; internal List<int> GetPrimes() { return rec(new List<int>(), 2, (list, i) => list.All(j => i % j != 0) ? list.AddAndReturn(i) : list); } internal PrimeList(int count) { rec = (list, i, func) => i < count ? rec(func(list, i), ++i, func) : list; } public IEnumerator<int> GetEnumerator() { foreach (var prime in GetPrimes()) { yield return prime; } } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<int>)this).GetEnumerator(); } }
なんとなく,見た目すっきりしたようにも見えるけど,何がしたいのか自分でもよくわかりません(^^;;
さらにコンストラクタ.引数countを直接ラムダ式に埋め込むのではなく,あるラムダ式の引数に渡してその結果(戻り値)がラムダ式になるようなもの(Haskellでいう部分適用のイメージ)を使うことにすると,こんな感じになるのかしら?
internal PrimeList(int count) { Func<int, Func<List<int>, int, Func<List<int>, int, List<int>>, List<int>>> partial = m => (list, i, func) => i < m ? rec(func(list, i), ++i, func) : list; rec = partial(count); }
目が痛くなること請け合い...