C#3.0で関数プログラミング(モドキ)
関数型言語の真似事をやってみます。(追記)タイトルを修正。
using System; using System.Collections.Generic; using System.Functionals; namespace System.Functionals { public delegate T BinaryFunction<T>(T arg1, T arg2); public static class Functional { // Lispのcarみたいなモノ public static T Head<T> (this IEnumerable<T> source) { IEnumerator<T> e = source.GetEnumerator (); if (e.MoveNext ()) return e.Current; throw new ArgumentException (); } // Lispのcdrみたいなモノ public static IEnumerable<T> Tail<T> (this IEnumerable<T> source) { using (IEnumerator<T> e = source.GetEnumerator ()) { if (e.MoveNext()) while (e.MoveNext ()) yield return e.Current; } } // 畳み込み(左) public static T FoldLeft<T> (this IEnumerable<T> source, T acc, BinaryFunction<T> func) { T head = source.Head (); IEnumerable<T> tail = source.Tail (); IEnumerator<T> e = tail.GetEnumerator (); if (!e.MoveNext ()) return func (acc, head); else return tail.FoldLeft (func (acc, head), func); } // 畳み込み(右) public static T FoldRight<T> (this IEnumerable<T> source, T acc, BinaryFunction<T> func) { T head = source.Head (); IEnumerable<T> tail = source.Tail (); IEnumerator<T> e = tail.GetEnumerator (); if (!e.MoveNext ()) return func (head, acc); else return func (head, tail.FoldRight (acc, func)); } public static void ForEach<T> (this IEnumerable<T> source, Action<T> action) { foreach (T arg in source) action (arg); } } } static class Program { static void Main () { int nums = new {1, 2, 3 }; // 先頭要素 Console.WriteLine (nums.Head ()); // 残りのリスト nums.Tail ().ForEach (delegate (int x) { Console.Write ("{0},", x);}); Console.WriteLine (); // 畳み込み(左) = (((0 - 1) - 2) - 3) Console.WriteLine ("FoldLeft = {0}", nums.FoldLeft (0, (x, y) => x - y)); // 畳み込み(右) = (1 - (2 - (3 - 0))) Console.WriteLine ("FoldRight = {0}", nums.FoldRight (0, (x, y) => x - y)); } } /* 1 2,3, FoldLeft = -6 FoldRight = 2 */
効率は無視の方向でお願いします。昨日考えていたネタだったんですが、急な仕事でスライド登板です。(^^;
あ、考えてみたらコレ、LINQじゃなくて拡張メソッドの使い方ですね。C#3.0で関数・・・というタイトルにすべきでした。(^^;