/// Public domain code by Christopher Diggins /// http://www.cat-language.com using System; namespace Cat { #region delegate types public delegate void Accessor(object o); public delegate bool PairAccessor(object x, object y); public delegate object FoldFxn(object x, object y); public delegate object MapFxn(object o); public delegate object RangeGenFxn(int n); public delegate bool FilterFxn(object o); #endregion /// /// This is a quasi-functional list. It implements common functional list operations in a non-mutable /// manner and behaves as a mutable iterator. /// There are several different specializations of each class which reduce the complexity of many /// common algorithms, and offer optimized versions of the classes for different scenarios. /// public abstract class FList { #region abstract functions public abstract void ForEach(Accessor a); public abstract FList GetIter(); public abstract FList GotoNext(); public abstract object Head(); public abstract bool IsEmpty(); #endregion #region static delegate functions public static FilterFxn ComposeFilters(FilterFxn f, FilterFxn g) { return delegate(object x) { return f(x) && g(x); }; } public static FilterFxn NegateFilter(FilterFxn f) { return delegate(object x) { return !f(x); }; } #endregion #region static data static EmptyList nil = new EmptyList(); #endregion #region static functions public static FList Concat(FList first, FList second) { if (second.IsEmpty()) return first; if (first.IsEmpty()) return second; return new ConcatPair(first, second); } public static FList Gen(object o, MapFxn next, FilterFxn cond) { return new Generator(o, next, cond); } public static FList RangeGen(RangeGenFxn f, int first, int count) { return new RangeGenerator(f, first, count); } public static FList MakeRepeater(Object o) { return new FListRepeater(o); } public static FList Nil() { return nil; } public static FList MakeUnit(object x) { return new Unit(x); } public static FList MakePair(object first, object second) { return new Pair(first, second); } public static FList Cons(object x, FList list) { return new ConsCell(x, list); } public static void PairwiseForEach(PairAccessor f, FList x, FList y) { if (x.IsEmpty() || y.IsEmpty()) return; if (f(x.Head(), y.Head())) return; PairwiseForEach(f, x.Tail(), y.Tail()); } public static bool AreListsEqual(FList x, FList y) { // Same memory address? if (x == y) return true; // Known finite lists, and known infinite lists are never equal. if (x.IsKnownFinite() && y.IsKnownInfinite()) return false; if (x.IsKnownInfinite() && y.IsKnownFinite()) return false; // If either list is empty, then we can simply look to see if the other one is as well if (x.IsEmpty()) return y.IsEmpty(); if (y.IsEmpty()) return false; // since we know from the previous condition that both x and y aren't empty. // Compare the count if it is easy. if (x.IsKnownFinite() && y.IsKnownFinite()) if (x.Count() != y.Count()) return false; // We have to resort to pairwise comparisons bool ret = true; PairAccessor f = delegate(Object first, Object second) { if (!first.Equals(second)) return ret = false; return true; }; PairwiseForEach(f, x, y); return ret; } #endregion #region virtual functions public override bool Equals(object obj) { if (!(obj is FList)) return false; return AreListsEqual(this, obj as FList); } public override int GetHashCode() { return base.GetHashCode(); } public virtual int Count() { int result = 0; ForEach(delegate(object o) { result += 1; }); return result; } public virtual bool IsKnownFinite() { // most lists are known to be finite, so this is the default return true; } public virtual bool IsKnownInfinite() { // most lists are finite return false; } public virtual object Fold(object init, FoldFxn f) { ForEach(delegate(object o) { init = f(init, o); }); return init; } public virtual FList Map(MapFxn f) { return new MappedFList(this, f); } public virtual object Nth(int n) { FList iter = GetIter(); while (!iter.IsEmpty() && n != 0) { iter = iter.GotoNext(); --n; } if (n != 0) throw new Exception("out of range"); return iter.Head(); } public virtual FList Tail() { return GetIter().GotoNext(); } public virtual Object Last() { Object result = null; ForEach(delegate(Object o) { result = o; }); return result; } public virtual FList Filter(FilterFxn f) { return new FilteredFList(this, f); } public virtual FList DropN(int n) { FList ret = GetIter(); while (!ret.IsEmpty() && n != 0) { ret = ret.GotoNext(); --n; } return ret; } public virtual FList TakeN(int n) { switch (n) { case (0): return Nil(); case (1): return MakeUnit(Head()); case (2): return MakePair(Head(), Tail().Head()); } object[] a = new object[n]; int i = 0; FList iter = GetIter(); while (!iter.IsEmpty() && (i < n)) { a[i++] = iter.Head(); iter = iter.GotoNext(); } if (i < n) { return new RangedArray(a, 0, i); } else { return new FArray(a); } } public virtual FList TakeRange(int first, int count) { return DropN(first).TakeN(count); } public virtual FList TakeWhile(FilterFxn f) { int n = CountWhile(f); return TakeN(n); } public virtual FList DropWhile(FilterFxn f) { FList ret = GetIter(); while (!ret.IsEmpty() && f(ret.Head())) ret = ret.GotoNext(); return ret; } public virtual int CountWhile(FilterFxn f) { int cnt = 0; FList ret = GetIter(); while (!ret.IsEmpty() && f(ret.Head())) { ret = ret.GotoNext(); ++cnt; } return cnt; } public virtual FList Flatten() { return new FlattenedFList(this); } #endregion } public class EmptyList : FList { #region abstract function overrides public override void ForEach(Accessor a) { } public override FList GetIter() { return this; } public override FList GotoNext() { return this; } public override object Head() { throw new Exception("empty list"); } public override bool IsEmpty() { return true; } #endregion #region virtual function overrides public override int Count() { return 0; } public override int CountWhile(FilterFxn f) { return 0; } public override FList TakeN(int n) { return this; } public override FList DropN(int n) { return this; } public override FList TakeRange(int first, int count) { return this; } public override FList TakeWhile(FilterFxn f) { return this; } public override FList DropWhile(FilterFxn f) { return this; } public override FList Filter(FilterFxn f) { return this; } public override FList Map(MapFxn f) { return this; } public override object Fold(object init, FoldFxn f) { return init; } public override object Nth(int n) { throw new Exception("empty list"); } public override object Last() { throw new Exception("empty list"); } public override FList Tail() { return this; } #endregion } public class Unit : FList { #region fields object m; #endregion #region constructors public Unit(object x) { m = x; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { a(m); } public override FList GetIter() { return this; } public override FList GotoNext() { return Nil(); } public override bool IsEmpty() { return false; } public override object Head() { return m; } #endregion #region virtual function overrides public override int Count() { return 1; } public override int CountWhile(FilterFxn f) { return f(m) ? 1 : 0; } public override object Last() { return m; } public override FList Tail() { return Nil(); } public override FList Map(MapFxn f) { return MakeUnit(f(m)); } public override FList Filter(FilterFxn f) { if (f(m)) { return this; } else { return Nil(); } } public override object Fold(object init, FoldFxn f) { return f(init, m); } public override FList DropN(int n) { if (n == 0) return this; else return Nil(); } public override FList TakeN(int n) { if (n == 0) return Nil(); else return this; } public override FList DropWhile(FilterFxn f) { if (f(m)) return Nil(); else return this; } public override FList TakeWhile(FilterFxn f) { if (f(m)) return this; else return Nil(); } public override object Nth(int n) { if (n != 0) throw new Exception("out of range"); return m; } #endregion } public class Pair : FList { #region fields public object mFirst; public object mSecond; #endregion #region constructors public Pair(object first, object second) { mFirst = first; mSecond = second; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { a(mFirst); a(mSecond); } public override FList GetIter() { return this; } public override FList GotoNext() { return MakeUnit(mSecond); } public override bool IsEmpty() { return false; } public override object Head() { return mFirst; } #endregion #region virtual function overrides public override object Last() { return mSecond; } public override FList Tail() { return MakeUnit(mSecond); } public override int Count() { return 2; } public override int CountWhile(FilterFxn f) { return (f(mFirst) ? 1 : 0) + (f(mSecond) ? 1 : 0); } public override FList Map(MapFxn f) { return MakePair(f(mFirst), f(mSecond)); } public override FList Filter(FilterFxn f) { if (f(mFirst)) { if (f(mSecond)) return this; else return MakeUnit(mFirst); } else { if (f(mSecond)) return MakeUnit(mSecond); else return Nil(); } } public override object Fold(object init, FoldFxn f) { return f(f(init, mFirst), mSecond); } public override FList DropN(int n) { switch (n) { case (0) : return this; case (1) : return MakeUnit(mSecond); default : return Nil(); } } public override FList TakeN(int n) { switch (n) { case (0): return Nil(); case (1): return MakeUnit(mFirst); default: return this; } } public override object Nth(int n) { switch (n) { case (0): return mFirst; case (1): return mSecond; default: throw new Exception("out of range"); } } public override FList DropWhile(FilterFxn f) { if (!f(mFirst)) return this; if (!f(mSecond)) return MakeUnit(mSecond); return Nil(); } public override FList TakeWhile(FilterFxn f) { if (!f(mFirst)) return Nil(); if (!f(mSecond)) return MakeUnit(mFirst); return this; } #endregion } public class ConcatPair : FList { #region fields FList mFirst; int mFirstCount; FList mSecond; #endregion #region constructors public ConcatPair(FList first, FList second) : this(first, second, first.Count()) { } public ConcatPair(FList first, FList second, int firstCount) { mFirst = first; mFirstCount = firstCount; mSecond = second; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { mFirst.ForEach(a); mSecond.ForEach(a); } public override FList GetIter() { if (mFirstCount == 0) { return mSecond.GetIter(); } else { return new ConcatPair(mFirst.GetIter(), mSecond, mFirstCount); } } public override FList GotoNext() { if (mFirstCount == 0) throw new Exception("internal error, corrupt ConcatPair"); if (mFirstCount == 1) { return mSecond.GetIter(); } else { mFirst.GotoNext(); --mFirstCount; } return this; } public override bool IsEmpty() { return mFirst.IsEmpty() && mSecond.IsEmpty(); } public override Object Head() { if (mFirstCount != 0) return mFirst.Head(); else return mSecond.Head(); } #endregion #region abstract function overrides public override int Count() { return mFirstCount + mSecond.Count(); } public override int CountWhile(FilterFxn f) { return mFirst.CountWhile(f) + mSecond.CountWhile(f); } public override object Nth(int n) { if (n < mFirstCount) return mFirst.Nth(n); else return mSecond.Nth(n - mFirstCount); } public override FList Tail() { if (mFirst.IsEmpty()) return mSecond.Tail(); return Concat(mFirst.Tail(), mSecond); } public override Object Last() { return mSecond.Last(); } /// /// Overriding Filter allows concatenation to retain some of its optimizations. /// public override FList Filter(FilterFxn f) { return new ConcatPair(new FilteredFList(mFirst, f), new FilteredFList(mSecond, f)); } /// /// Overriding Map allows concatenation to retain some of its optimizations. /// public override FList Map(MapFxn f) { return Concat(new MappedFList(mFirst, f), new MappedFList(mSecond, f)); } public override FList DropN(int n) { if (n >= mFirstCount) { return mSecond.DropN(n - mFirstCount); } else { return Concat(mFirst.DropN(n), mSecond); } } public override FList TakeN(int n) { if (n >= mFirstCount) { return Concat(mFirst, mSecond.TakeN(mFirstCount)); } else { return mFirst.TakeN(n); } } public override FList TakeWhile(FilterFxn f) { FList tmp = mFirst.TakeWhile(f); if (tmp.Count() == mFirstCount) { return Concat(mFirst, mSecond.TakeWhile(f)); } else { return tmp; } } public override FList DropWhile(FilterFxn f) { FList tmp = mFirst.DropWhile(f); if (tmp.IsEmpty()) { return mSecond.DropWhile(f); } else { return Concat(tmp, mSecond); } } #endregion } public class FArray : FList { #region fields object[] m; #endregion #region constructors public FArray(FList list, int n) { m = new object[n]; int i = 0; list.ForEach(delegate(Object x) { if (i < n) m[i++] = x; }); } public FArray(FList list) : this(list, list.Count()) { } public FArray(object[] x) { m = x; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { foreach (object o in m) a(o); } public override FList GetIter() { return new RangedArray(m, 0, m.Length); } public override FList GotoNext() { throw new Exception("CArray used CRangedArray as an iterator, therefore GotoNext() can never be called on it."); } public override bool IsEmpty() { return Count() == 0; } public override int Count() { return m.Length; } public override Object Head() { return m[0]; } #endregion #region virtual function overrides public override object Nth(int n) { return m[n]; } public override Object Last() { return m[Count() - 1]; } public override FList DropN(int n) { return TakeRange(n, Count() - n); } public override FList TakeN(int n) { return TakeRange(0, n); } public override FList TakeRange(int first, int count) { if ((first == 0) && (count == Count())) return this; if (first + count > Count()) count = Count() - first; switch (count) { case (0): return Nil(); case (1): return MakeUnit(m[0]); case (2): return MakePair(m[0], m[1]); default: return new RangedArray(m, first, count); } } public override FList DropWhile(FilterFxn f) { int n = CountWhile(f); return TakeRange(n, Count() - n); } public override int CountWhile(FilterFxn f) { for (int i = 0; i < Count(); ++i) { if (!f(Nth(i))) return i; } return Count(); } #endregion } public class RangedArray : FList { #region fields object[] m; int mFirst; int mCount; #endregion #region cosntructors public RangedArray(object[] a, int first, int count) { if (count < 0) throw new Exception("Invalid count"); if (first < 0) throw new Exception("Invalid range, first index must be non-negative"); if (first + count > a.Length) count = a.Length - first; m = a; mFirst = first; mCount = count; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { for (int i = mFirst; i < mFirst + mCount; ++i) { a(m[i]); } } public override FList GetIter() { return new RangedArray(m, mFirst, mCount); } public override FList GotoNext() { mFirst += 1; mCount -= 1; return this; } public override bool IsEmpty() { return mCount == 0; } public override Object Head() { return m[mFirst]; } #endregion #region virtual function overrides public override int Count() { return mCount; } public override int CountWhile(FilterFxn f) { for (int i = 0; i < Count(); ++i) { if (!f(Nth(i))) return i; } return Count(); } public override FList DropWhile(FilterFxn f) { int n = CountWhile(f); return TakeRange(n, mCount - n); } public override object Nth(int n) { return m[n + mFirst]; } public override Object Last() { return m[mFirst + mCount - 1]; } public override FList DropN(int n) { return TakeRange(n, Count() - n); } public override FList TakeN(int n) { return TakeRange(0, n); } public override FList TakeRange(int first, int count) { if (first + count > mCount) count = mCount - first; switch (count) { case (0): return Nil(); case (1): return MakeUnit(m[first + mFirst]); case (2): return MakePair(m[first + mFirst], m[first + mFirst + 1]); default: return new RangedArray(m, mFirst, count); } } #endregion } public class MappedFList : FList { #region fields MapFxn mMap; FList mList; #endregion #region constructors public MappedFList(FList list, MapFxn map) { mList = list; mMap = map; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { mList.ForEach(delegate(object x) { a(mMap(x)); }); } public override FList GetIter() { return new MappedFList(mList.GetIter(), mMap); } public override FList GotoNext() { mList = mList.GotoNext(); return this; } public override bool IsEmpty() { return mList.IsEmpty(); } public override object Head() { return mMap(mList.Head()); } #endregion #region virtual function overrides public override bool IsKnownFinite() { return mList.IsKnownFinite(); } public override int Count() { return mList.Count(); } public override object Last() { return mMap(mList.Last()); } public override object Nth(int n) { return mMap(mList.Nth(n)); } public override FList DropN(int n) { return new MappedFList(mList.DropN(n), mMap); } public override FList TakeN(int n) { return new MappedFList(mList.TakeN(n), mMap); } public override FList TakeRange(int first, int count) { return new MappedFList(mList.TakeRange(first, count), mMap); } #endregion } public class FilteredFList : FList { #region fields FilterFxn mFilter; FList mList; #endregion #region constructors public FilteredFList(FList list, FilterFxn filter) { // this way we are guaranteed that either mList has a first value // satisfying the filter, or is empty. mList = list.DropWhile(NegateFilter(filter)); mFilter = filter; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { mList.ForEach(delegate(object x) { if (mFilter(x)) a(x); }); } public override FList GetIter() { return new FilteredFList(mList.GetIter(), mFilter); } public override FList GotoNext() { mList = mList.GotoNext(); while (!mList.IsEmpty() && !mFilter(mList.Head())) { mList = mList.GotoNext(); } if (mList.IsEmpty()) return Nil(); return this; } public override object Head() { return mList.Head(); } public override bool IsEmpty() { return mList.IsEmpty(); } #endregion #region virtual function overrides public override int CountWhile(FilterFxn f) { return mList.CountWhile(ComposeFilters(f, mFilter)); } public override bool IsKnownFinite() { return mList.IsKnownFinite(); } #endregion } public class ConsCell : FList { #region fields object mHead; FList mTail; #endregion #region constructors public ConsCell(object head, FList rest) { mHead = head; mTail = rest; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { a(mHead); mTail.ForEach(a); } public override FList GetIter() { return new ConsCell(mHead, mTail); } public override FList GotoNext() { if (mTail.IsEmpty()) { return Nil(); } mHead = mTail.Head(); mTail = mTail.Tail(); return this; } public override bool IsEmpty() { return false; } public override object Head() { return mHead; } #endregion #region virtual function overrides public override bool IsKnownFinite() { return false; } public override bool IsKnownInfinite() { return false; } public override int Count() { return 1 + mTail.Count(); } public override int CountWhile(FilterFxn f) { if (!f(mHead)) return 0; return 1 + mTail.CountWhile(f); } public override object Nth(int n) { if (n == 0) return mHead; else return mTail.Nth(n - 1); } public override FList DropN(int n) { if (n == 0) return this; else return mTail.DropN(n - 1); } #endregion } public class FListRepeater : FList { #region fields object mObject; #endregion #region constructors public FListRepeater(Object o) { mObject = o; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { // Breaks only when a throws an exception while (true) { a(mObject); } } public override FList GetIter() { return this; } public override FList GotoNext() { return this; } public override bool IsEmpty() { return false; } public override Object Head() { return mObject; } #endregion #region virtual override functions public override bool IsKnownFinite() { return false; } public override bool IsKnownInfinite() { return true; } public override object Nth(int n) { return mObject; } public override FList Tail() { return this; } public override Object Last() { return mObject; } public override FList Filter(FilterFxn f) { if (f(mObject)) return this; else return Nil(); } public override int Count() { throw new Exception("infinite list"); } public override int CountWhile(FilterFxn f) { if (!f(mObject)) return 0; throw new Exception("inifinite"); } public override object Fold(object init, FoldFxn f) { if (f(init, mObject) != init) throw new Exception("diverges"); else return init; } public override FList Map(MapFxn f) { return new FListRepeater(f(mObject)); } public override FList DropN(int n) { return this; } public override FList TakeN(int n) { return RangeGen(delegate(int i) { return mObject; }, 0, n); } public override FList TakeWhile(FilterFxn f) { return Gen(mObject, delegate(Object x) { return mObject; }, f); } public override FList DropWhile(FilterFxn f) { return this; } #endregion } public class RangeGenerator : FList { #region fields RangeGenFxn mFxn; int mFirst; int mCount; #endregion #region constructors public RangeGenerator(RangeGenFxn f, int first, int count) { mFxn = f; mFirst = first; mCount = count; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { for (int i = mFirst; i < mCount; ++i) { a(mFxn(i)); } } public override FList GetIter() { return new RangeGenerator(mFxn, mFirst, mCount); } public override FList GotoNext() { ++mFirst; --mCount; return this; } public override bool IsEmpty() { return mCount == 0; } public override Object Head() { return mFxn(mFirst); } #endregion #region virtual function overrides public override bool IsKnownFinite() { return true; } public override bool IsKnownInfinite() { return false; } public override int Count() { return mCount; } public override object Nth(int n) { return mFxn(n + mFirst); } public override FList Tail() { return DropN(1); } public override Object Last() { return mFxn(mFirst + mCount - 1); } public override FList DropN(int n) { return TakeRange(mFirst + n, mCount - n); } public override FList TakeN(int n) { return TakeRange(mFirst, n); } public override FList TakeRange(int first, int count) { if (count + first > mCount) count = mCount - first; switch (count) { case (0): return Nil(); case (1): return MakeUnit(mFxn(mFirst + first)); case (2): return MakePair(mFxn(mFirst + first), mFxn(mFirst + first + 1)); default: return new RangeGenerator(mFxn, mFirst + first, count); } } public override int CountWhile(FilterFxn f) { for (int i = 0; i < mCount; ++i) { if (!f(mFxn(i + mFirst))) return i; } return mCount; } public override FList DropWhile(FilterFxn f) { int n = CountWhile(f); return TakeRange(n, mCount - n); } #endregion } public class Generator : FList { #region fields object mFirst; MapFxn mNext; FilterFxn mCond; #endregion #region constructors public Generator(object first, MapFxn next, FilterFxn cond) { mFirst = first; mNext = next; mCond = cond; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { object cur = mFirst; while (mCond(cur)) { a(cur); cur = mNext(cur); } } public override FList GetIter() { return new Generator(mFirst, mNext, mCond); } public override object Head() { return mFirst; } public override bool IsEmpty() { return !mCond(mFirst); } public override FList GotoNext() { mFirst = mNext(mFirst); return this; } #endregion #region virtual function overrides public override bool IsKnownFinite() { return false; } public override bool IsKnownInfinite() { return false; } public override FList Tail() { return Gen(mNext(mFirst), mNext, mCond); } public override FList TakeWhile(FilterFxn f) { if (!mCond(mFirst) || !f(mFirst)) return Nil(); return Gen(mFirst, mNext, ComposeFilters(f, mCond)); } public override int CountWhile(FilterFxn f) { int n = 0; object cur = mFirst; while (mCond(cur)) { ++n; cur = mNext(cur); } return n; } public override FList DropWhile(FilterFxn f) { object cur = mFirst; while (mCond(cur) && f(cur)) { cur = mNext(cur); } if (mCond(cur)) return Nil(); return Gen(cur, mNext, mCond); } #endregion } public class FlattenedFList : FList { #region fields FList mList; #endregion #region constructor public FlattenedFList(FList list) { mList = list; } #endregion #region abstract function overrides public override void ForEach(Accessor a) { mList.ForEach(delegate(object o) { (o as FList).ForEach(a); }); } public override FList GetIter() { return new FlattenedFList(mList.GetIter()); } public override FList GotoNext() { mList = mList.GotoNext(); return this; } public override object Head() { return (mList.Head() as FList).Head(); } public override bool IsEmpty() { return (!IsEmpty()) && ((mList.Head() as FList).IsEmpty()); } #endregion } }