What makes a good lazy procedure? And how to do it?

I’ve been playing around with iterators/sequences/collections that partition to a set stride. For instance, given a collection with 16 elements and a stride argument of 3; I can generate a collection with 6 elements, the first 5 are sub-collections of count 3 and the last a sub-collection of count 1.

Now I’m wondering if I put these in a library on GitHub, should they be structured under the standard library’s “lazy” group of procedures? Or just separate types?

Oh, is there a modern guide for making lazy algorithm types? All the ones I’ve seen so far are from the Swift 1.0 days (when the algorithms were free functions instead of extensions of Sequence/Collection). Yes, I know I’m using busted vs. modern for a language only a few years old.

···


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

Hi Daryle,

I think this is a perfect case for an addition to the existing Lazy suite (and IMO would make a good evolution proposal too, as this kind of “chunked” splitting is a useful feature). You’re right though, there isn’t a good guide out there for how to do this (calling any intrepid blogger who wants to write one…)

Here’s a sketch of how it would fit into lazy. This is with the latest toolchain from master, which makes things a LOT easier now that IndexDistance is dead. It’s slightly inefficient because it re-uses Index from Base for its index, it would be more efficient to use a start/end pair for the chunks but that’s a lot more code :slight_smile:

What’s also interesting is you could (with conditional conformance now that’s landed) make it a RandomAccessCollection if the base were random access, but not if the base is bidirectional, because you need to be able to calculate the size of the last element in constant time.

struct LazyChunkedCollection<Base: Collection> {
    let base: Base
    let size: Int
}

extension LazyChunkedCollection: Collection {
    typealias Index = Base.Index
    typealias Element = Base.SubSequence
    
    var startIndex: Index { return base.startIndex }
    var endIndex: Index { return base.endIndex }
    
    subscript(i: Index) -> Element {
        return base[i..<index(after: i)]
    }
    
    func index(after i: Index) -> Index {
        return base.index(i, offsetBy: size, limitedBy: base.endIndex) ?? base.endIndex
    }
}

// Keep the laziness transitive
extension LazyChunkedCollection: LazyCollectionProtocol { }

// Extending this protocol will make this feature appear on the .lazy property of Collection
extension LazyCollectionProtocol {
    // Elements/elements are a way to avoid redundent wrapping
    func chunked(into chunksOf: Int) -> LazyChunkedCollection<Elements> {
        return LazyChunkedCollection(base: elements, size: chunksOf)
    }
}

let l = Array(0..<10).lazy.chunked(into: 3)
for x in l {
    for y in x {
        print(y, terminator: ",")
    }
    print()
}
0,1,2,
3,4,5,
6,7,8,
9,

···

On Dec 29, 2017, at 18:40, Daryle Walker via swift-users <swift-users@swift.org> wrote:

I’ve been playing around with iterators/sequences/collections that partition to a set stride. For instance, given a collection with 16 elements and a stride argument of 3; I can generate a collection with 6 elements, the first 5 are sub-collections of count 3 and the last a sub-collection of count 1.

Now I’m wondering if I put these in a library on GitHub, should they be structured under the standard library’s “lazy” group of procedures? Or just separate types?

Oh, is there a modern guide for making lazy algorithm types? All the ones I’ve seen so far are from the Swift 1.0 days (when the algorithms were free functions instead of extensions of Sequence/Collection). Yes, I know I’m using busted vs. modern for a language only a few years old.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

1 Like

Hi Daryle,

I think this is a perfect case for an addition to the existing Lazy suite (and IMO would make a good evolution proposal too, as this kind of “chunked” splitting is a useful feature). You’re right though, there isn’t a good guide out there for how to do this (calling any intrepid blogger who wants to write one…)

Here’s a sketch of how it would fit into lazy. This is with the latest toolchain from master, which makes things a LOT easier now that IndexDistance is dead. It’s slightly inefficient because it re-uses Index from Base for its index, it would be more efficient to use a start/end pair for the chunks but that’s a lot more code :slight_smile:

I saw that I missed this discussion when I skipped out for 1.5 months. I’m not sure what the problem with IndexDistance was; abstraction is generally a good thing. Wouldn’t any awkwardness with “let x: IndexDistance = 0” affect ALL types besides Int? If you have a problem with that, then the solution would be to redo Swift’s literal-handling model.

What’s also interesting is you could (with conditional conformance now that’s landed) make it a RandomAccessCollection if the base were random access, but not if the base is bidirectional, because you need to be able to calculate the size of the last element in constant time.

Is this active, at least in Xcode 9.2? Because I couldn’t get the obvious:

extension ChunkedCollection: RandomAccessCollection where Base: RandomAccessCollection {
    //…
}

to work. (An extension with constraints can’t have an inheritance clause.)

···

On Jan 2, 2018, at 11:57 PM, Ben Cohen <ben_cohen@apple.com> wrote:


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

I got a trial at <https://github.com/CTMacUser/SectionedSequences>.

···

On Jan 2, 2018, at 11:57 PM, Ben Cohen <ben_cohen@apple.com> wrote:

I think this is a perfect case for an addition to the existing Lazy suite (and IMO would make a good evolution proposal too, as this kind of “chunked” splitting is a useful feature). You’re right though, there isn’t a good guide out there for how to do this (calling any intrepid blogger who wants to write one…)

Here’s a sketch of how it would fit into lazy. This is with the latest toolchain from master, which makes things a LOT easier now that IndexDistance is dead. It’s slightly inefficient because it re-uses Index from Base for its index, it would be more efficient to use a start/end pair for the chunks but that’s a lot more code :slight_smile:

What’s also interesting is you could (with conditional conformance now that’s landed) make it a RandomAccessCollection if the base were random access, but not if the base is bidirectional, because you need to be able to calculate the size of the last element in constant time.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

I saw that I missed this discussion when I skipped out for 1.5 months. I’m not sure what the problem with IndexDistance was; abstraction is generally a good thing.

Abstraction is a means, not an end. Abstractions that result in impedance with little benefit are bad. IndexDistance was a clear case of this.

What’s also interesting is you could (with conditional conformance now that’s landed) make it a RandomAccessCollection if the base were random access, but not if the base is bidirectional, because you need to be able to calculate the size of the last element in constant time.

Is this active, at least in Xcode 9.2?

Xcode 9.2 shipped with a variant of Swift 4.0. IndexDistance should be removed in 4.1 and later. You can try it in Xcode today though by downloading the latest master or 4.1 snapshot toolchain from swift.org <http://swift.org/>.

···

On Jan 8, 2018, at 9:04 AM, Daryle Walker <darylew@mac.com> wrote:

I meant conditional conformance, not the IndexDistance change.

···

On Jan 8, 2018, at 3:57 PM, Ben Cohen <ben_cohen@apple.com> wrote:

Is this active, at least in Xcode 9.2?

Xcode 9.2 shipped with a variant of Swift 4.0. IndexDistance should be removed in 4.1 and later. You can try it in Xcode today though by downloading the latest master or 4.1 snapshot toolchain from swift.org <http://swift.org/>.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

Conditional conformance isn't in the version of Swift that shipped with Xcode 9.2 either. Using the snapshot Ben suggested is a good way to try it out.

-Kyle

···

On Jan 8, 2018, at 1:28 PM, Daryle Walker via swift-users <swift-users@swift.org> wrote:

On Jan 8, 2018, at 3:57 PM, Ben Cohen <ben_cohen@apple.com <mailto:ben_cohen@apple.com>> wrote:

Is this active, at least in Xcode 9.2?

Xcode 9.2 shipped with a variant of Swift 4.0. IndexDistance should be removed in 4.1 and later. You can try it in Xcode today though by downloading the latest master or 4.1 snapshot toolchain from swift.org <http://swift.org/>.

I meant conditional conformance, not the IndexDistance change.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Terms of Service

Privacy Policy

Cookie Policy