//  Copyright © 2015 Rob Rix. All rights reserved.

extension CollectionType {
	public var uncons: (first: SubSequence._Element, rest: SubSequence)? {
		if !isEmpty {
			let some = self[startIndex..<startIndex.advancedBy(1)]
			return (first: some[some.startIndex], rest: dropFirst())
		}
		return nil
	}

	public var rest: SubSequence {
		return isEmpty
			? self[startIndex..<endIndex]
			: dropFirst()
	}
}

extension CollectionType where SubSequence: CollectionType, SubSequence.SubSequence == SubSequence {
	public var conses: AnyGenerator<(first: SubSequence._Element, rest: SubSequence)> {
		var current = uncons
		return anyGenerator {
			let next = current
			current = current?.rest.uncons
			return next
		}
	}

	public func fold<Out>(initial: Out, @noescape combine: (SubSequence._Element, Out) -> Out) -> Out {
		return self[indices].fold(initial, combine: combine)
	}
}


extension CollectionType where SubSequence == Self {
	public func fold<Out>(initial: Out, @noescape combine: (Generator.Element, Out) -> Out) -> Out {
		return first.map {
			combine($0, dropFirst().fold(initial, combine: combine))
		} ?? initial
	}
}

//  Copyright © 2015 Rob Rix. All rights reserved.

extension CollectionType {
	public var uncons: (first: SubSequence._Element, rest: SubSequence)? {
		if !isEmpty {
			let some = self[startIndex..<startIndex.advancedBy(1)]
			return (first: some[some.startIndex], rest: dropFirst())
		}
		return nil
	}

	public var rest: SubSequence {
		return isEmpty
			? self[startIndex..<endIndex]
			: dropFirst()
	}
}

extension CollectionType where SubSequence: CollectionType, SubSequence.SubSequence == SubSequence {
	public var conses: AnyGenerator<(first: SubSequence._Element, rest: SubSequence)> {
		var current = uncons
		return anyGenerator {
			let next = current
			current = current?.rest.uncons
			return next
		}
	}
}


extension CollectionType where SubSequence == Self {
	public func fold<Out>(initial: Out, @noescape combine: (Generator.Element, Out) -> Out) -> Out {
		return first.map {
			combine($0, dropFirst().fold(initial, combine: combine))
		} ?? initial
	}
}

--- 
+++ 
@@ -25,6 +25,10 @@
 			return next
 		}
 	}
+
+	public func fold<Out>(initial: Out, @noescape combine: (SubSequence._Element, Out) -> Out) -> Out {
+		return self[indices].fold(initial, combine: combine)
+	}
 }
 
 
Add a fold overload that will work on Array.
