Skip to content

Instantly share code, notes, and snippets.

@danielctull
Last active April 4, 2018 10:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielctull/ec521f3fc2aadabb17d38f716e55c5f7 to your computer and use it in GitHub Desktop.
Save danielctull/ec521f3fc2aadabb17d38f716e55c5f7 to your computer and use it in GitHub Desktop.
/// A `Collection` that contains the same elements as this one,
/// in the reversed order.
public protocol ReversedCollectionProtocol: BidirectionalCollection {
associatedtype Elements: Collection
where Elements.Iterator.Element == Iterator.Element
var elements: Elements { get }
}
extension ReversedCollection: ReversedCollectionProtocol {
public var elements: Base {
return _base
}
}
extension ReversedCollectionProtocol {
// Reversing a reversed collection returns the original collection.
public func reversed() -> Elements {
return elements
}
}
extension LazyCollectionProtocol
where
Self: BidirectionalCollection,
Elements: ReversedCollectionProtocol {
// Reversing a lazy reversed collection returns a lazy representation of the original collection.
public func reversed() -> LazyCollection<Elements.Elements> {
return elements.elements.lazy
}
}
extension LazyCollectionProtocol
where
Self: BidirectionalCollection,
Elements: BidirectionalCollection {
// Reversing a lazy collection returns a lazy representation of
// the reversed representation of the original collection.
public func reversed() -> LazyCollection<ReversedCollection<Elements>> {
return elements.reversed().lazy
}
}
// MARK:- Tests
func printtype(_ name: String, _ value: Any) {
print("")
print(name)
print(type(of: value))
}
let array = [0,1,3,4]
let reversed = array.reversed()
let reversedreversed = reversed.reversed()
printtype("array:", array)
printtype("reversed:", reversed)
printtype("reversed reversed:", reversedreversed)
print("\n=====")
let oldreversedreversed: ReversedCollection<ReversedCollection<[Int]>> = reversed.reversed()
printtype("old reversed reversed:", oldreversedreversed)
let newreversedreversed: [Int] = reversed.reversed()
printtype("new reversed reversed:", newreversedreversed)
print("\n=====")
let lazy = array.lazy
let lazyreversed = lazy.reversed()
let lazyreversedreversed = lazyreversed.reversed()
printtype("lazy:", lazy)
printtype("lazy reversed:", lazyreversed)
printtype("lazy reversed reversed:", lazyreversedreversed)
print("\n=====")
let oldlazyreversedreversed: LazyCollection<ReversedCollection<ReversedCollection<[Int]>>> = lazyreversed.reversed()
printtype("old lazy reversed reversed:", oldlazyreversedreversed)
let newlazyreversedreversed: LazyCollection<[Int]> = lazyreversed.reversed()
printtype("new lazy reversed reversed:", newlazyreversedreversed)
print("\n=====")
let reversedlazy = reversed.lazy
let reversedlazyreversed = reversedlazy.reversed()
printtype("lazy:", lazy)
printtype("reversed lazy:", reversedlazy)
printtype("reversed lazy reversed:", reversedlazyreversed)
print("\n=====")
let oldreversedlazyreversed: LazyCollection<ReversedCollection<ReversedCollection<[Int]>>> = reversedlazy.reversed()
printtype("old reversed lazy reversed:", oldreversedlazyreversed)
let newreversedlazyreversed: LazyCollection<[Int]> = reversedlazy.reversed()
printtype("new reversed lazy reversed:", newreversedlazyreversed)
@danielctull
Copy link
Author

danielctull commented Apr 2, 2018

I tried and failed to constrain LazyCollectionProtocol when its elements are a ReversedCollection, but couldn't get that to work with the generics of ReversedCollection – perhaps it's not possible, and that's the reason the stdlib currently has LazyCollectionProtocol to deal with LazyCollection types?

Taking inspiration from this I made a ReversedCollectionProtocol to constrain the lazy collection so that it can return a lazy view on the original elements when the elements are already reversed.

@danielctull
Copy link
Author

danielctull commented Apr 4, 2018

I've tried changing the extension on LazyCollectionProtocol so that its Elements is ReversedCollection (to avoid needed this unwanted new ReversedCollectionProtocol protocol), but it requires the generic type to be specified. I've tried to use BidirectionalCollection:

extension LazyCollectionProtocol
  where
  Self: BidirectionalCollection,
  Elements == ReversedCollection<BidirectionalCollection>

but I get the error:

using 'BidirectionalCollection' as a concrete type conforming to protocol 'BidirectionalCollection' is not supported

I'm not too sure how else I can constrain this extension. I think ideally it'd be nice to add a new generic into the mix, something like the following:

extension LazyCollectionProtocol
  where
  Self: BidirectionalCollection,
  Elements == ReversedCollection<T> {

  // Reversing a lazy reversed collection returns a lazy representation of the original collection.
  public func reversed() -> LazyCollection<T> {
    return elements._base.lazy
  }
}

but unsurprisingly this gives an an error

use of undeclared type 'T'

I've looked through the Language Reference section in the Swift book (for version 4.1) around Extensions and Generic Where Clauses to see if there was anything in the language that I was missing that could help add this constraint, but I can't find anything there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment