Multi dimensional - iterator, Iterator2D, Iterator3D


(Ted van Gaalen) #1

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.

so, I’ve made the functions [iterator, iterator2D, iterator3D] (hereunder)
wich btw clearly demonstrate the power and flexibility of Swift.

Very straightforward, and efficient (i assume) just like the classical for;; loop.
It works quite well in my sources.

As a spin-off, I’ve extended these to iterators for matrices 2D and cubes? 3D...

Question:
Perhaps implementing “multi dimensional iterator functions
in Swift might be a good idea. so that is no longer necessary to nest/nest/nest iterators.

Met vriendelijke groeten, sorry for my “intensity” in discussing the classical for;;
I'll have to rethink this for;; again..
Thanks, Ted.

Any remarks ( all ), suggestions about the code hereunder: ?

protocol NumericType
{
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
}

extension Double : NumericType { }
extension Float : NumericType { }
extension CGFloat: NumericType { }
extension Int : NumericType { }
extension Int8 : NumericType { }
extension Int16 : NumericType { }
extension Int32 : NumericType { }
extension Int64 : NumericType { }
extension UInt : NumericType { }
extension UInt8 : NumericType { }
extension UInt16 : NumericType { }
extension UInt32 : NumericType { }
extension UInt64 : NumericType { }

/// Simple iterator with generic parameters, with just a few lines of code.
/// for most numeric types (see above)
/// Usage Example:
///
/// iterate(xmax, { $0 > xmin}, -xstep,
/// {x in
/// print("x = \(x)")
/// return true // returning false acts like a break
/// } )
///
/// -Parameter vstart: Initial value
/// -Parameter step: The iteration stepping value.
/// -Parameter test: A block with iteration test. e.g. {$0 > 10}
///
/// -Parameter block: A block to be executed with each step.
/// The block must include a return true (acts like "continue")
/// or false (acts like "break")
/// -Please Note:
/// There is minor precision loss ca: 1/1000 ... 1/500
/// when iterating with floating point numbers.
/// However, in most cases this can be safely ignored.
/// made by ted van gaalen.

func iterate<T:NumericType> (
                    vstart: T,
                   _ vstep: T,
                   _ test: (T) -> Bool,
                   _ block: (T) -> Bool )
{
    var current = vstart
    
    while test(current) && block(current)
    {
        current = current + vstep
    }
}

/// X,Y 2D matrix (table) iterator with generic parameters
func iterate2D<T:NumericType> (
     xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
   _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
   _ block: (T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            dontStop = block(xcurrent, ycurrent)
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

/// X,Y,Z 3D (cubic) iterator with generic parameters:

func iterate3D<T:NumericType> (
    xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
  _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
  _ zstart: T, _ zstep: T, _ ztest: (T) -> Bool,
      _ block: (T,T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    var zcurrent = zstart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            zcurrent = zstart
            while ztest(zcurrent) && dontStop
            {
                dontStop = block(xcurrent, ycurrent, zcurrent)
                zcurrent = zcurrent + zstep
            }
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

func testIterator()
{
    iterate(0.0, 0.5, {$0 < 1000.00000} ,
            { value in
                print("Value = \(value) ")
                return true
    } )

    let startv: CGFloat = -20.0
    let stepv: CGFloat = 0.5
    
    iterate(startv, stepv, {$0 < 1000.00000} ,
            { val in
                print("R = \(val)")
                return true
    } )

    let tolerance = 0.01 // boundary tolerance for floating point type
    
    iterate2D( 0.0, 10.0, { $0 < 100.0 + tolerance } ,
               0.0, 5.0, { $0 < 50.0 + tolerance } ,
               {x,y in
                print("x = \(x) y = \(y)")
                return true // false from block stops iterating ( like break)
                } )

    iterate3D( 0.0, 10.0, { $0 < 30.0 } , // x
               0.0, 5.0, { $0 < 20.0 } , // y
               10.0, -5.0, { $0 > -10.0 } , // z
               {x,y,z in
                    print("x = \(x) y = \(y) z = \(z)")
                    if z < 0.0
                    {
                        print ( "** z value \(z) is below zero! **" )
                        
                        return false // (acts as break in for;:wink:
                    }
                    return true // return stmt is obligatory (continue)
               } )
}


(Jaden Geller) #2

What benefit do Iterator2D and Iterator3D provide that nesting does not?

···

On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org> wrote:

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.

so, I’ve made the functions [iterator, iterator2D, iterator3D] (hereunder)
wich btw clearly demonstrate the power and flexibility of Swift.

Very straightforward, and efficient (i assume) just like the classical for;; loop.
It works quite well in my sources.

As a spin-off, I’ve extended these to iterators for matrices 2D and cubes? 3D...

Question:
Perhaps implementing “multi dimensional iterator functions
in Swift might be a good idea. so that is no longer necessary to nest/nest/nest iterators.

Met vriendelijke groeten, sorry for my “intensity” in discussing the classical for;;
I'll have to rethink this for;; again..
Thanks, Ted.

Any remarks ( all ), suggestions about the code hereunder: ?

protocol NumericType
{
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
}

extension Double : NumericType { }
extension Float : NumericType { }
extension CGFloat: NumericType { }
extension Int : NumericType { }
extension Int8 : NumericType { }
extension Int16 : NumericType { }
extension Int32 : NumericType { }
extension Int64 : NumericType { }
extension UInt : NumericType { }
extension UInt8 : NumericType { }
extension UInt16 : NumericType { }
extension UInt32 : NumericType { }
extension UInt64 : NumericType { }

/// Simple iterator with generic parameters, with just a few lines of code.
/// for most numeric types (see above)
/// Usage Example:
///
/// iterate(xmax, { $0 > xmin}, -xstep,
/// {x in
/// print("x = \(x)")
/// return true // returning false acts like a break
/// } )
///
/// -Parameter vstart: Initial value
/// -Parameter step: The iteration stepping value.
/// -Parameter test: A block with iteration test. e.g. {$0 > 10}
///
/// -Parameter block: A block to be executed with each step.
/// The block must include a return true (acts like "continue")
/// or false (acts like "break")
/// -Please Note:
/// There is minor precision loss ca: 1/1000 ... 1/500
/// when iterating with floating point numbers.
/// However, in most cases this can be safely ignored.
/// made by ted van gaalen.

func iterate<T:NumericType> (
                    vstart: T,
                   _ vstep: T,
                   _ test: (T) -> Bool,
                   _ block: (T) -> Bool )
{
    var current = vstart
    
    while test(current) && block(current)
    {
        current = current + vstep
    }
}

/// X,Y 2D matrix (table) iterator with generic parameters
func iterate2D<T:NumericType> (
     xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
   _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
   _ block: (T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            dontStop = block(xcurrent, ycurrent)
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

/// X,Y,Z 3D (cubic) iterator with generic parameters:

func iterate3D<T:NumericType> (
    xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
  _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
  _ zstart: T, _ zstep: T, _ ztest: (T) -> Bool,
      _ block: (T,T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    var zcurrent = zstart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            zcurrent = zstart
            while ztest(zcurrent) && dontStop
            {
                dontStop = block(xcurrent, ycurrent, zcurrent)
                zcurrent = zcurrent + zstep
            }
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

func testIterator()
{
    iterate(0.0, 0.5, {$0 < 1000.00000} ,
            { value in
                print("Value = \(value) ")
                return true
    } )

    let startv: CGFloat = -20.0
    let stepv: CGFloat = 0.5
    
    iterate(startv, stepv, {$0 < 1000.00000} ,
            { val in
                print("R = \(val)")
                return true
    } )

    let tolerance = 0.01 // boundary tolerance for floating point type
    
    iterate2D( 0.0, 10.0, { $0 < 100.0 + tolerance } ,
               0.0, 5.0, { $0 < 50.0 + tolerance } ,
               {x,y in
                print("x = \(x) y = \(y)")
                return true // false from block stops iterating ( like break)
                } )

    iterate3D( 0.0, 10.0, { $0 < 30.0 } , // x
               0.0, 5.0, { $0 < 20.0 } , // y
               10.0, -5.0, { $0 > -10.0 } , // z
               {x,y,z in
                    print("x = \(x) y = \(y) z = \(z)")
                    if z < 0.0
                    {
                        print ( "** z value \(z) is below zero! **" )
                        
                        return false // (acts as break in for;:wink:
                    }
                    return true // return stmt is obligatory (continue)
               } )
}

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


(Chris Lattner) #3

Hi Ted,

I know that you’re very passionate about the removal of C style for loops, but any direction to add back features to compensate for them will need to wait until Stage 2 of Swift 4’s planning cycle.

-Chris

···

On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen <tedvgiosdev@gmail.com> wrote:

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.


(Ted van Gaalen) #4

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.

Hi Ted,

I know that you’re very passionate about the removal of C style for loops,

Hi Chris,

I am trying to channel my sometimes chaotic energy into positive things,
which means I should not have only criticism, but try
to find positive alternatives and suggestions for the things
that I don’t like.

but any direction to add back features to compensate for them will need to wait until Stage 2 of Swift 4’s planning cycle.

Yes, of course, I understand that. Forgot to mention that.
It is more intended as to viewing aspects of iteration in general.

The code example was initially intended as a convenience “workaround”
(usable without any alterations in Swift 2.x and higher)
for those of us who are using the for;; frequently,

However, I for me find it now even better then just a workaround
especially for 2 and 3D iterations.

So it could be that I won’t miss the for;; that much as I thought.
as the power and flexibility of Swift mostly allows us to add
own extensions as alternative solutions when desired
and that is very cool!

Kind Regards
TedvG

(Note that that my biggest challenge in life is to coordinate
the chaos that always storms in my mind due to heavy
ADHD aspects (which also have advantages)
and to communicate with “other lifeforms”
like human beings because of that.)

···

On 31.07.2016, at 07:07, Chris Lattner <clattner@apple.com> wrote:

On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen <tedvgiosdev@gmail.com> wrote:


(Ted van Gaalen) #5

What benefit do Iterator2D and Iterator3D provide that nesting does not?

Hi Jaden,
well, simply because of hiding/enclosing repetitive functionality
like with every other programming element is convenient,
prevents errors and from writing the same over and over again.
That is why there are functions.
but you already know that, of course.
Kind Regards
TedvG

···

On 31.07.2016, at 04:28, jaden.geller@gmail.com wrote:

On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.

so, I’ve made the functions [iterator, iterator2D, iterator3D] (hereunder)
wich btw clearly demonstrate the power and flexibility of Swift.

Very straightforward, and efficient (i assume) just like the classical for;; loop.
It works quite well in my sources.

As a spin-off, I’ve extended these to iterators for matrices 2D and cubes? 3D...

Question:
Perhaps implementing “multi dimensional iterator functions
in Swift might be a good idea. so that is no longer necessary to nest/nest/nest iterators.

Met vriendelijke groeten, sorry for my “intensity” in discussing the classical for;;
I'll have to rethink this for;; again..
Thanks, Ted.

Any remarks ( all ), suggestions about the code hereunder: ?

protocol NumericType
{
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
}

extension Double : NumericType { }
extension Float : NumericType { }
extension CGFloat: NumericType { }
extension Int : NumericType { }
extension Int8 : NumericType { }
extension Int16 : NumericType { }
extension Int32 : NumericType { }
extension Int64 : NumericType { }
extension UInt : NumericType { }
extension UInt8 : NumericType { }
extension UInt16 : NumericType { }
extension UInt32 : NumericType { }
extension UInt64 : NumericType { }

/// Simple iterator with generic parameters, with just a few lines of code.
/// for most numeric types (see above)
/// Usage Example:
///
/// iterate(xmax, { $0 > xmin}, -xstep,
/// {x in
/// print("x = \(x)")
/// return true // returning false acts like a break
/// } )
///
/// -Parameter vstart: Initial value
/// -Parameter step: The iteration stepping value.
/// -Parameter test: A block with iteration test. e.g. {$0 > 10}
///
/// -Parameter block: A block to be executed with each step.
/// The block must include a return true (acts like "continue")
/// or false (acts like "break")
/// -Please Note:
/// There is minor precision loss ca: 1/1000 ... 1/500
/// when iterating with floating point numbers.
/// However, in most cases this can be safely ignored.
/// made by ted van gaalen.

func iterate<T:NumericType> (
                    vstart: T,
                   _ vstep: T,
                   _ test: (T) -> Bool,
                   _ block: (T) -> Bool )
{
    var current = vstart
    
    while test(current) && block(current)
    {
        current = current + vstep
    }
}

/// X,Y 2D matrix (table) iterator with generic parameters
func iterate2D<T:NumericType> (
     xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
   _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
   _ block: (T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            dontStop = block(xcurrent, ycurrent)
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

/// X,Y,Z 3D (cubic) iterator with generic parameters:

func iterate3D<T:NumericType> (
    xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
  _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
  _ zstart: T, _ zstep: T, _ ztest: (T) -> Bool,
      _ block: (T,T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    var zcurrent = zstart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            zcurrent = zstart
            while ztest(zcurrent) && dontStop
            {
                dontStop = block(xcurrent, ycurrent, zcurrent)
                zcurrent = zcurrent + zstep
            }
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

func testIterator()
{
    iterate(0.0, 0.5, {$0 < 1000.00000} ,
            { value in
                print("Value = \(value) ")
                return true
    } )

    let startv: CGFloat = -20.0
    let stepv: CGFloat = 0.5
    
    iterate(startv, stepv, {$0 < 1000.00000} ,
            { val in
                print("R = \(val)")
                return true
    } )

    let tolerance = 0.01 // boundary tolerance for floating point type
    
    iterate2D( 0.0, 10.0, { $0 < 100.0 + tolerance } ,
               0.0, 5.0, { $0 < 50.0 + tolerance } ,
               {x,y in
                print("x = \(x) y = \(y)")
                return true // false from block stops iterating ( like break)
                } )

    iterate3D( 0.0, 10.0, { $0 < 30.0 } , // x
               0.0, 5.0, { $0 < 20.0 } , // y
               10.0, -5.0, { $0 > -10.0 } , // z
               {x,y,z in
                    print("x = \(x) y = \(y) z = \(z)")
                    if z < 0.0
                    {
                        print ( "** z value \(z) is below zero! **" )
                        
                        return false // (acts as break in for;:wink:
                    }
                    return true // return stmt is obligatory (continue)
               } )
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Erica Sadun) #6

I'm replying on Swift-Users and bcc'ing in Swift-Evolution to comply with the core team's request to focus SE on the current mission statement.

At some point soon, Russ Bishop's PR https://github.com/apple/swift/pull/3600 will be incorporated into Swift 3. This PR adds `prefix(while:)` and `drop(while:)` to finish implementing SE-0045. Once that's done, you can combine `sequence(first:, next:)` and `prefix(while:)` to into a single function `sequence(first:, next:, while:)` like this:

public func sequence<T>(first: T, next: (T) -> T?, while test: (T) -> Bool) -> UnfoldSequence<T, UnfoldSequence<T, (T?, Bool)>> {
    return sequence(first: first, next: next).prefix(while: test)
}

The combined sequence/prefix call allows you to create loops like this:

for outerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <= 64 }) {
    for innerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <= 64 }) {
        print(outerIndex, innerIndex)
    }
}

These loops can be nested. break and continue work. You can use tuples for multiple arguments. While I'd like to see a combined form adopted into Swift 4b (the deferred "sugar"), it isn't a high priority.

-- E

···

On Jul 31, 2016, at 7:18 AM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org> wrote:

On 31.07.2016, at 04:28, jaden.geller@gmail.com <mailto:jaden.geller@gmail.com> wrote:

What benefit do Iterator2D and Iterator3D provide that nesting does not?

Hi Jaden,
well, simply because of hiding/enclosing repetitive functionality
like with every other programming element is convenient,
prevents errors and from writing the same over and over again.
That is why there are functions.
but you already know that, of course.
Kind Regards
TedvG

On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.

so, I’ve made the functions [iterator, iterator2D, iterator3D] (hereunder)
wich btw clearly demonstrate the power and flexibility of Swift.

Very straightforward, and efficient (i assume) just like the classical for;; loop.
It works quite well in my sources.

As a spin-off, I’ve extended these to iterators for matrices 2D and cubes? 3D...

Question:
Perhaps implementing “multi dimensional iterator functions
in Swift might be a good idea. so that is no longer necessary to nest/nest/nest iterators.

Met vriendelijke groeten, sorry for my “intensity” in discussing the classical for;;
I'll have to rethink this for;; again..
Thanks, Ted.

Any remarks ( all ), suggestions about the code hereunder: ?

protocol NumericType
{
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
}

extension Double : NumericType { }
extension Float : NumericType { }
extension CGFloat: NumericType { }
extension Int : NumericType { }
extension Int8 : NumericType { }
extension Int16 : NumericType { }
extension Int32 : NumericType { }
extension Int64 : NumericType { }
extension UInt : NumericType { }
extension UInt8 : NumericType { }
extension UInt16 : NumericType { }
extension UInt32 : NumericType { }
extension UInt64 : NumericType { }

/// Simple iterator with generic parameters, with just a few lines of code.
/// for most numeric types (see above)
/// Usage Example:
///
/// iterate(xmax, { $0 > xmin}, -xstep,
/// {x in
/// print("x = \(x)")
/// return true // returning false acts like a break
/// } )
///
/// -Parameter vstart: Initial value
/// -Parameter step: The iteration stepping value.
/// -Parameter test: A block with iteration test. e.g. {$0 > 10}
///
/// -Parameter block: A block to be executed with each step.
/// The block must include a return true (acts like "continue")
/// or false (acts like "break")
/// -Please Note:
/// There is minor precision loss ca: 1/1000 ... 1/500
/// when iterating with floating point numbers.
/// However, in most cases this can be safely ignored.
/// made by ted van gaalen.

func iterate<T:NumericType> (
                    vstart: T,
                   _ vstep: T,
                   _ test: (T) -> Bool,
                   _ block: (T) -> Bool )
{
    var current = vstart
    
    while test(current) && block(current)
    {
        current = current + vstep
    }
}

/// X,Y 2D matrix (table) iterator with generic parameters
func iterate2D<T:NumericType> (
     xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
   _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
   _ block: (T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            dontStop = block(xcurrent, ycurrent)
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

/// X,Y,Z 3D (cubic) iterator with generic parameters:

func iterate3D<T:NumericType> (
    xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
  _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
  _ zstart: T, _ zstep: T, _ ztest: (T) -> Bool,
      _ block: (T,T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    var zcurrent = zstart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            zcurrent = zstart
            while ztest(zcurrent) && dontStop
            {
                dontStop = block(xcurrent, ycurrent, zcurrent)
                zcurrent = zcurrent + zstep
            }
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

func testIterator()
{
    iterate(0.0, 0.5, {$0 < 1000.00000} ,
            { value in
                print("Value = \(value) ")
                return true
    } )

    let startv: CGFloat = -20.0
    let stepv: CGFloat = 0.5
    
    iterate(startv, stepv, {$0 < 1000.00000} ,
            { val in
                print("R = \(val)")
                return true
    } )

    let tolerance = 0.01 // boundary tolerance for floating point type
    
    iterate2D( 0.0, 10.0, { $0 < 100.0 + tolerance } ,
               0.0, 5.0, { $0 < 50.0 + tolerance } ,
               {x,y in
                print("x = \(x) y = \(y)")
                return true // false from block stops iterating ( like break)
                } )

    iterate3D( 0.0, 10.0, { $0 < 30.0 } , // x
               0.0, 5.0, { $0 < 20.0 } , // y
               10.0, -5.0, { $0 > -10.0 } , // z
               {x,y,z in
                    print("x = \(x) y = \(y) z = \(z)")
                    if z < 0.0
                    {
                        print ( "** z value \(z) is below zero! **" )
                        
                        return false // (acts as break in for;:wink:
                    }
                    return true // return stmt is obligatory (continue)
               } )
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Garth Snyder) #7

Jaden Geller: What benefit do Iterator2D and Iterator3D provide that nesting does not?

Ted F.A. van Gaalen: well, simply because of hiding/enclosing repetitive functionality like with every other programming element is convenient, prevents errors and from writing the same over and over again.

I’m not sure why you’re trying to avoid sequences - as far as the actual values you are iterating over, your needs seem to be pretty well covered by the existing stride() family.

Given that you just want to flatten the call sites, perhaps something like this would suit your needs:

let xrange = stride(from: 0.0, to: 30.0, by: 10.0)
let yrange = stride(from: 0.0, to: 20.0, by: 5.0)
let zrange = stride(from: 10.0, to:-10.0, by:-5.0)

for (x, y, z) in cartesianProduct(xrange, yrange, zrange) {
    print("x = \(x) y = \(y) z = \(z)")
    if z < 0.0 {
        print ( "** z value \(z) is below zero! **" )
        break
    }
}
Using strides removes the need for any of the NumericType labels, and cartesianProduct() would be usable for any (reiterable) sequences, not just your designated types.

If you want a language issue to obsess over, I suggest the inflexibility of tuples, which force you to have a separate wrapper for each number of dimensions. :slight_smile:

I would have thought there’d be an off-the-shelf cartesian product somewhere that you could use, but it doesn’t seem to come up in the Google. It’d look something like this. (This is causing a compiler crash in Xcode 8b3 and so is not completely vetted, but it’s probably close…)

func cartesianProduct<U, V where U: Sequence, V == U.Iterator.Element>(_ args: U...) ->
    AnyIterator<[V]>
{
    var iterators = args.map { $0.makeIterator() }
    var values = [V?]()
    for i in 0 ... iterators.endIndex {
        values.append(iterators[i].next())
    }
    var done = values.contains { $0 == nil }
    
    return AnyIterator() {
        if done {
            return nil
        }
        let thisValue = values.map { $0! }
        var i = args.endIndex
        repeat {
            values[i] = iterators[i].next()
            if values[i] != nil {
                return thisValue
            } else if i == 0 {
                done = true
                return thisValue
            } else {
                iterators[i] = args[i].makeIterator()
                values[i] = iterators[i].next()
                i -= 1
            }
        } while true
    }
}

func cartesianProduct<U, V where U: Sequence, V == U.Iterator.Element>(_ a: U, _ b: U, _ c: U) ->
    AnyIterator<(V, V, V)>
{
    var subIterator: AnyIterator<[V]> = cartesianProduct(a, b, c)
    return AnyIterator() {
        if let value = subIterator.next() {
            return (value[0], value[1], value[2])
        }
        return nil
    }
}
Garth

···

That is why there are functions.
but you already know that, of course.
Kind Regards
TedvG

On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.

so, I’ve made the functions [iterator, iterator2D, iterator3D] (hereunder)
wich btw clearly demonstrate the power and flexibility of Swift.

Very straightforward, and efficient (i assume) just like the classical for;; loop.
It works quite well in my sources.

As a spin-off, I’ve extended these to iterators for matrices 2D and cubes? 3D...

Question:
Perhaps implementing “multi dimensional iterator functions
in Swift might be a good idea. so that is no longer necessary to nest/nest/nest iterators.

Met vriendelijke groeten, sorry for my “intensity” in discussing the classical for;;
I'll have to rethink this for;; again..
Thanks, Ted.

Any remarks ( all ), suggestions about the code hereunder: ?

protocol NumericType
{
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
}

extension Double : NumericType { }
extension Float : NumericType { }
extension CGFloat: NumericType { }
extension Int : NumericType { }
extension Int8 : NumericType { }
extension Int16 : NumericType { }
extension Int32 : NumericType { }
extension Int64 : NumericType { }
extension UInt : NumericType { }
extension UInt8 : NumericType { }
extension UInt16 : NumericType { }
extension UInt32 : NumericType { }
extension UInt64 : NumericType { }

/// Simple iterator with generic parameters, with just a few lines of code.
/// for most numeric types (see above)
/// Usage Example:
///
/// iterate(xmax, { $0 > xmin}, -xstep,
/// {x in
/// print("x = \(x)")
/// return true // returning false acts like a break
/// } )
///
/// -Parameter vstart: Initial value
/// -Parameter step: The iteration stepping value.
/// -Parameter test: A block with iteration test. e.g. {$0 > 10}
///
/// -Parameter block: A block to be executed with each step.
/// The block must include a return true (acts like "continue")
/// or false (acts like "break")
/// -Please Note:
/// There is minor precision loss ca: 1/1000 ... 1/500
/// when iterating with floating point numbers.
/// However, in most cases this can be safely ignored.
/// made by ted van gaalen.

func iterate<T:NumericType> (
                    vstart: T,
                   _ vstep: T,
                   _ test: (T) -> Bool,
                   _ block: (T) -> Bool )
{
    var current = vstart
    
    while test(current) && block(current)
    {
        current = current + vstep
    }
}

/// X,Y 2D matrix (table) iterator with generic parameters
func iterate2D<T:NumericType> (
     xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
   _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
   _ block: (T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            dontStop = block(xcurrent, ycurrent)
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

/// X,Y,Z 3D (cubic) iterator with generic parameters:

func iterate3D<T:NumericType> (
    xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
  _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
  _ zstart: T, _ zstep: T, _ ztest: (T) -> Bool,
      _ block: (T,T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    var zcurrent = zstart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            zcurrent = zstart
            while ztest(zcurrent) && dontStop
            {
                dontStop = block(xcurrent, ycurrent, zcurrent)
                zcurrent = zcurrent + zstep
            }
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

func testIterator()
{
    iterate(0.0, 0.5, {$0 < 1000.00000} ,
            { value in
                print("Value = \(value) ")
                return true
    } )

    let startv: CGFloat = -20.0
    let stepv: CGFloat = 0.5
    
    iterate(startv, stepv, {$0 < 1000.00000} ,
            { val in
                print("R = \(val)")
                return true
    } )

    let tolerance = 0.01 // boundary tolerance for floating point type
    
    iterate2D( 0.0, 10.0, { $0 < 100.0 + tolerance } ,
               0.0, 5.0, { $0 < 50.0 + tolerance } ,
               {x,y in
                print("x = \(x) y = \(y)")
                return true // false from block stops iterating ( like break)
                } )

    iterate3D( 0.0, 10.0, { $0 < 30.0 } , // x
               0.0, 5.0, { $0 < 20.0 } , // y
               10.0, -5.0, { $0 > -10.0 } , // z
               {x,y,z in
                    print("x = \(x) y = \(y) z = \(z)")
                    if z < 0.0
                    {
                        print ( "** z value \(z) is below zero! **" )
                        
                        return false // (acts as break in for;:wink:
                    }
                    return true // return stmt is obligatory (continue)
               } )
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Ted van Gaalen) #8

Hi Erica

That would also be a workable solution, but imho still too tedious as
it has been so for many years, with nested iteration statements…
many times this is for;; for;; for tables and for;;for;;for;; for 3D structuring.
  
Swift offers nice features (like protocols and generics as you know) to improve this.

- I no longer have to nest for;; s so, Now I rather do this:
Your example can already be coded like this:

   iterate2D( 1, 2, { $0 < 64 } ,
              1, 2, { $0 < 64 } ,
                  {outerIndex,innerIndex in
                      print (outerIndex,InnerIndex)
                      
                      return true // Obligatory. return “false" to break
                   } )

With no chances in Swift, this already works like a charm!
Imho much more readable and compact,

Uses - AFAICS from a programmers’s perspective - no
underlying deep collection based coding with Sequence. etc.

I am already deploying it in my own apps e.g. l
(replaced for;; for;; for;; in the app)

By using this new iterator…() functions my coding gets leaner
and errors are easier to spot.

Actual working code with Swift 2.x here:

  func generateTiles()
  {
        let w: Float = 20 // tile size
        let h: Float = 5
        let l: Float = 5
        
        let xstart: Float = -120
        let ystart: Float = -60
        let zstart: Float = -10
        
        let xend: Float = 120
        let yend: Float = 60
        let zend: Float = 10
        
        let tolerance:Float = 0.001 // float drift compensation
        
        iterate3D( xstart, w * 1.2, { $0 < xend + tolerance } ,
                   ystart, h * 1.2, { $0 < yend + tolerance } ,
                   zstart, l * 1.2, { $0 < zend + tolerance } ,
                   {
                    x,y,z in
                    self.addTile(x,y,z,
                                 w,h,l)
                    return true
                   } )
    }

This generates a group of blocks or tiles in my Apple TV app (under construction)
like the one you can see in the image “Cloinckz” on my website www.tedvg.com <http://www.tedvg.com/>.

I also prefer the one dimensional iterate(.. too above the for;; or stride()

One could extend these iterator…() functions by adding closures for pre and post iteration handling,
like for printing headers and footers before and/or after a complete [inner] iteration.

Note that breaking with *return false* -which is equivalent to the “break” stmt in
a classical for;; - does not only leave a nested iteration, but also the outer ones.
(maybe a TODO to make individual level- break possible) As it is now, If one
wants to break at the deep iteration level, then one should nest this using 1D iterators.

Anyway, this is just a thought starting to think about multi-dimensional iterators,
and other (encapsulation?) of multi dimensional data as well.
In any case for 2D because table data is used very frequently in many apps. as
most data are in tables.

You won’t believe this :o) but in a sense I might not make so much fuzz anymore
to keep the for;; as this proves to me that I can solve things much better that I thought.
So, I have to rethink this.

Kind Regards
Ted
www.ravelnotes.com <http://www.ravelnotes.com/>

···

On 31.07.2016, at 18:33, Erica Sadun <erica@ericasadun.com> wrote:

I'm replying on Swift-Users and bcc'ing in Swift-Evolution to comply with the core team's request to focus SE on the current mission statement.

At some point soon, Russ Bishop's PR https://github.com/apple/swift/pull/3600 will be incorporated into Swift 3. This PR adds `prefix(while:)` and `drop(while:)` to finish implementing SE-0045. Once that's done, you can combine `sequence(first:, next:)` and `prefix(while:)` to into a single function `sequence(first:, next:, while:)` like this:

public func sequence<T>(first: T, next: (T) -> T?, while test: (T) -> Bool) -> UnfoldSequence<T, UnfoldSequence<T, (T?, Bool)>> {
    return sequence(first: first, next: next).prefix(while: test)
}

The combined sequence/prefix call allows you to create loops like this:

for outerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <= 64 }) {
    for innerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <= 64 }) {
        print(outerIndex, innerIndex)
    }
}

These loops can be nested. break and continue work. You can use tuples for multiple arguments. While I'd like to see a combined form adopted into Swift 4b (the deferred "sugar"), it isn't a high priority.

-- E

On Jul 31, 2016, at 7:18 AM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 31.07.2016, at 04:28, jaden.geller@gmail.com <mailto:jaden.geller@gmail.com> wrote:

What benefit do Iterator2D and Iterator3D provide that nesting does not?

Hi Jaden,
well, simply because of hiding/enclosing repetitive functionality
like with every other programming element is convenient,
prevents errors and from writing the same over and over again.
That is why there are functions.
but you already know that, of course.
Kind Regards
TedvG

On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.

so, I’ve made the functions [iterator, iterator2D, iterator3D] (hereunder)
wich btw clearly demonstrate the power and flexibility of Swift.

Very straightforward, and efficient (i assume) just like the classical for;; loop.
It works quite well in my sources.

As a spin-off, I’ve extended these to iterators for matrices 2D and cubes? 3D...

Question:
Perhaps implementing “multi dimensional iterator functions
in Swift might be a good idea. so that is no longer necessary to nest/nest/nest iterators.

Met vriendelijke groeten, sorry for my “intensity” in discussing the classical for;;
I'll have to rethink this for;; again..
Thanks, Ted.

Any remarks ( all ), suggestions about the code hereunder: ?

protocol NumericType
{
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
}

extension Double : NumericType { }
extension Float : NumericType { }
extension CGFloat: NumericType { }
extension Int : NumericType { }
extension Int8 : NumericType { }
extension Int16 : NumericType { }
extension Int32 : NumericType { }
extension Int64 : NumericType { }
extension UInt : NumericType { }
extension UInt8 : NumericType { }
extension UInt16 : NumericType { }
extension UInt32 : NumericType { }
extension UInt64 : NumericType { }

/// Simple iterator with generic parameters, with just a few lines of code.
/// for most numeric types (see above)
/// Usage Example:
///
/// iterate(xmax, { $0 > xmin}, -xstep,
/// {x in
/// print("x = \(x)")
/// return true // returning false acts like a break
/// } )
///
/// -Parameter vstart: Initial value
/// -Parameter step: The iteration stepping value.
/// -Parameter test: A block with iteration test. e.g. {$0 > 10}
///
/// -Parameter block: A block to be executed with each step.
/// The block must include a return true (acts like "continue")
/// or false (acts like "break")
/// -Please Note:
/// There is minor precision loss ca: 1/1000 ... 1/500
/// when iterating with floating point numbers.
/// However, in most cases this can be safely ignored.
/// made by ted van gaalen.

func iterate<T:NumericType> (
                    vstart: T,
                   _ vstep: T,
                   _ test: (T) -> Bool,
                   _ block: (T) -> Bool )
{
    var current = vstart
    
    while test(current) && block(current)
    {
        current = current + vstep
    }
}

/// X,Y 2D matrix (table) iterator with generic parameters
func iterate2D<T:NumericType> (
     xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
   _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
   _ block: (T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            dontStop = block(xcurrent, ycurrent)
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

/// X,Y,Z 3D (cubic) iterator with generic parameters:

func iterate3D<T:NumericType> (
    xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
  _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
  _ zstart: T, _ zstep: T, _ ztest: (T) -> Bool,
      _ block: (T,T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    var zcurrent = zstart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            zcurrent = zstart
            while ztest(zcurrent) && dontStop
            {
                dontStop = block(xcurrent, ycurrent, zcurrent)
                zcurrent = zcurrent + zstep
            }
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

func testIterator()
{
    iterate(0.0, 0.5, {$0 < 1000.00000} ,
            { value in
                print("Value = \(value) ")
                return true
    } )

    let startv: CGFloat = -20.0
    let stepv: CGFloat = 0.5
    
    iterate(startv, stepv, {$0 < 1000.00000} ,
            { val in
                print("R = \(val)")
                return true
    } )

    let tolerance = 0.01 // boundary tolerance for floating point type
    
    iterate2D( 0.0, 10.0, { $0 < 100.0 + tolerance } ,
               0.0, 5.0, { $0 < 50.0 + tolerance } ,
               {x,y in
                print("x = \(x) y = \(y)")
                return true // false from block stops iterating ( like break)
                } )

    iterate3D( 0.0, 10.0, { $0 < 30.0 } , // x
               0.0, 5.0, { $0 < 20.0 } , // y
               10.0, -5.0, { $0 > -10.0 } , // z
               {x,y,z in
                    print("x = \(x) y = \(y) z = \(z)")
                    if z < 0.0
                    {
                        print ( "** z value \(z) is below zero! **" )
                        
                        return false // (acts as break in for;:wink:
                    }
                    return true // return stmt is obligatory (continue)
               } )
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Saagar Jha) #9

With your method, don't you need to write a new method for every dimension?

···

On Mon, Aug 1, 2016 at 08:43 Ted F.A. van Gaalen via swift-users < swift-users@swift.org> wrote:

Hi Erica

That would also be a workable solution, but imho still too tedious as
it has been so for many years, with nested iteration statements…
many times this is for;; for;; for tables and for;;for;;for;; for 3D
structuring.

Swift offers nice features (like protocols and generics as you know) to
improve this.

- I no longer have to nest for;; s so, Now I rather do this:
Your example can already be coded like this:

   iterate2D( 1, 2, { $0 < 64 } ,
              1, 2, { $0 < 64 } ,
                  {outerIndex,innerIndex in
                      print (outerIndex,InnerIndex)

                      return true // Obligatory. return “false" to break
                   } )

With no chances in Swift, this already works like a charm!
Imho much more readable and compact,

Uses - AFAICS from a programmers’s perspective - no
underlying deep collection based coding with Sequence. etc.

I am already deploying it in my own apps e.g. l
(replaced for;; for;; for;; in the app)

By using this new iterator…() functions my coding gets leaner
and errors are easier to spot.

Actual working code with Swift 2.x here:

  func generateTiles()
  {
        let w: Float = 20 // tile size
        let h: Float = 5
        let l: Float = 5

        let xstart: Float = -120
        let ystart: Float = -60
        let zstart: Float = -10

        let xend: Float = 120
        let yend: Float = 60
        let zend: Float = 10

        let tolerance:Float = 0.001 // float drift compensation

        iterate3D( xstart, w * 1.2, { $0 < xend + tolerance } ,
                   ystart, h * 1.2, { $0 < yend + tolerance } ,
                   zstart, l * 1.2, { $0 < zend + tolerance } ,
                   {
                    x,y,z in
                    self.addTile(x,y,z,
                                 w,h,l)
                    return true
                   } )
    }

This generates a group of blocks or tiles in my Apple TV app (under
construction)
like the one you can see in the image “Cloinckz” on my website
www.tedvg.com.

I also prefer the one dimensional iterate(.. too above the for;; or
stride()

One could extend these iterator…() functions by adding closures for pre
and post iteration handling,
like for printing headers and footers before and/or after a complete
[inner] iteration.

Note that breaking with *return false* -which is equivalent to the “break”
stmt in
a classical for;; - does not only leave a nested iteration, but also the
outer ones.
(maybe a TODO to make individual level- break possible) As it is now, If
one
wants to break at the deep iteration level, then one should nest this
using 1D iterators.

Anyway, this is just a thought starting to think about multi-dimensional
iterators,
and other (encapsulation?) of multi dimensional data as well.
In any case for 2D because table data is used very frequently in many
apps. as
most data are in tables.

You won’t believe this :o) but in a sense I might not make so much fuzz
anymore
to keep the for;; as this proves to me that I can solve things much
better that I thought.
So, I have to rethink this.

Kind Regards
Ted
www.ravelnotes.com

On 31.07.2016, at 18:33, Erica Sadun <erica@ericasadun.com> wrote:

I'm replying on Swift-Users and bcc'ing in Swift-Evolution to comply with
the core team's request to focus SE on the current mission statement.

At some point soon, Russ Bishop's PR
https://github.com/apple/swift/pull/3600 will be incorporated into Swift
3. This PR adds `prefix(while:)` and `drop(while:)` to finish implementing
SE-0045. Once that's done, you can combine `sequence(first:, next:)` and
`prefix(while:)` to into a single function `sequence(first:, next:,
while:)` like this:

public func sequence<T>(first: T, next: (T) -> T?, while test: (T) ->
Bool) -> UnfoldSequence<T, UnfoldSequence<T, (T?, Bool)>> {
    return sequence(first: first, next: next).prefix(while: test)
}

The combined sequence/prefix call allows you to create loops like this:

for outerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <= 64
}) {
    for innerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <=
64 }) {
        print(outerIndex, innerIndex)
    }
}

These loops can be nested. break and continue work. You can use tuples
for multiple arguments. While I'd like to see a combined form adopted into
Swift 4b (the deferred "sugar"), it isn't a high priority.

-- E

On Jul 31, 2016, at 7:18 AM, Ted F.A. van Gaalen via swift-evolution < > swift-evolution@swift.org> wrote:

On 31.07.2016, at 04:28, jaden.geller@gmail.com wrote:

What benefit do Iterator2D and Iterator3D provide that nesting does not?

Hi Jaden,
well, simply because of hiding/enclosing repetitive functionality
like with every other programming element is convenient,
prevents errors and from writing the same over and over again.
That is why there are functions.
but you already know that, of course.
Kind Regards
TedvG

On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen via swift-evolution < > swift-evolution@swift.org> wrote:

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.

so, I’ve made the functions [iterator, iterator2D, iterator3D] (hereunder)
wich btw clearly demonstrate the power and flexibility of Swift.

Very straightforward, and efficient (i assume) just like the classical
for;; loop.
It works quite well in my sources.

As a spin-off, I’ve extended these to iterators for matrices 2D and
cubes? 3D...

Question:
Perhaps implementing “multi dimensional iterator functions
in Swift might be a good idea. so that is no longer necessary to
nest/nest/nest iterators.

Met vriendelijke groeten, sorry for my “intensity” in discussing the
classical for;;
I'll have to rethink this for;; again..
Thanks, Ted.

Any remarks ( all ), suggestions about the code hereunder: ?

protocol NumericType
{
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
}

extension Double : NumericType { }
extension Float : NumericType { }
extension CGFloat: NumericType { }
extension Int : NumericType { }
extension Int8 : NumericType { }
extension Int16 : NumericType { }
extension Int32 : NumericType { }
extension Int64 : NumericType { }
extension UInt : NumericType { }
extension UInt8 : NumericType { }
extension UInt16 : NumericType { }
extension UInt32 : NumericType { }
extension UInt64 : NumericType { }

/// Simple iterator with generic parameters, with just a few lines of code.
/// for most numeric types (see above)
/// Usage Example:
///
/// iterate(xmax, { $0 > xmin}, -xstep,
/// {x in
/// print("x = \(x)")
/// return true // returning false acts like a break
/// } )
///
/// -Parameter vstart: Initial value
/// -Parameter step: The iteration stepping value.
/// -Parameter test: A block with iteration test. e.g. {$0 > 10}
///
/// -Parameter block: A block to be executed with each step.
/// The block must include a return true (acts like "continue")
/// or false (acts like "break")
/// -Please Note:
/// There is minor precision loss ca: 1/1000 ... 1/500
/// when iterating with floating point numbers.
/// However, in most cases this can be safely ignored.
/// made by ted van gaalen.

func iterate<T:NumericType> (
                    vstart: T,
                   _ vstep: T,
                   _ test: (T) -> Bool,
                   _ block: (T) -> Bool )
{
    var current = vstart

    while test(current) && block(current)
    {
        current = current + vstep
    }
}

/// X,Y 2D matrix (table) iterator with generic parameters
func iterate2D<T:NumericType> (
     xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
   _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
   _ block: (T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart

    var dontStop = true

    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            dontStop = block(xcurrent, ycurrent)
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

/// X,Y,Z 3D (cubic) iterator with generic parameters:

func iterate3D<T:NumericType> (
    xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
  _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
  _ zstart: T, _ zstep: T, _ ztest: (T) -> Bool,
      _ block: (T,T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    var zcurrent = zstart

    var dontStop = true

    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            zcurrent = zstart
            while ztest(zcurrent) && dontStop
            {
                dontStop = block(xcurrent, ycurrent, zcurrent)
                zcurrent = zcurrent + zstep
            }
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

func testIterator()
{
    iterate(0.0, 0.5, {$0 < 1000.00000} ,
            { value in
                print("Value = \(value) ")
                return true
    } )

    let startv: CGFloat = -20.0
    let stepv: CGFloat = 0.5

    iterate(startv, stepv, {$0 < 1000.00000} ,
            { val in
                print("R = \(val)")
                return true
    } )

    let tolerance = 0.01 // boundary tolerance for floating point type

    iterate2D( 0.0, 10.0, { $0 < 100.0 + tolerance } ,
               0.0, 5.0, { $0 < 50.0 + tolerance } ,
               {x,y in
                print("x = \(x) y = \(y)")
                return true // false from block stops iterating ( like
break)
                } )

    iterate3D( 0.0, 10.0, { $0 < 30.0 } , // x
               0.0, 5.0, { $0 < 20.0 } , // y
               10.0, -5.0, { $0 > -10.0 } , // z
               {x,y,z in
                    print("x = \(x) y = \(y) z = \(z)")
                    if z < 0.0
                    {
                        print ( "** z value \(z) is below zero! **" )

                        return false // (acts as break in for;:wink:
                    }
                    return true // return stmt is obligatory (continue)
               } )
}

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

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

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


(Ted van Gaalen) #10

With your method, don't you need to write a new method for every dimension?

Hi Saagar,

Yes, one could solve this by writing a function
that propagates though all iteration levels, possibly recursively,
I might try to implement that.
left “as an exercise to the astute reader” :o)

Kind regards
Ted

···

On 01.08.2016, at 17:45, Saagar Jha <saagar@saagarjha.com> wrote:

On Mon, Aug 1, 2016 at 08:43 Ted F.A. van Gaalen via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hi Erica

That would also be a workable solution, but imho still too tedious as
it has been so for many years, with nested iteration statements…
many times this is for;; for;; for tables and for;;for;;for;; for 3D structuring.
  
Swift offers nice features (like protocols and generics as you know) to improve this.

- I no longer have to nest for;; s so, Now I rather do this:
Your example can already be coded like this:

   iterate2D( 1, 2, { $0 < 64 } ,
              1, 2, { $0 < 64 } ,
                  {outerIndex,innerIndex in
                      print (outerIndex,InnerIndex)
                      
                      return true // Obligatory. return “false" to break
                   } )

With no chances in Swift, this already works like a charm!
Imho much more readable and compact,

Uses - AFAICS from a programmers’s perspective - no
underlying deep collection based coding with Sequence. etc.

I am already deploying it in my own apps e.g. l
(replaced for;; for;; for;; in the app)

By using this new iterator…() functions my coding gets leaner
and errors are easier to spot.

Actual working code with Swift 2.x here:

  func generateTiles()
  {
        let w: Float = 20 // tile size
        let h: Float = 5
        let l: Float = 5
        
        let xstart: Float = -120
        let ystart: Float = -60
        let zstart: Float = -10
        
        let xend: Float = 120
        let yend: Float = 60
        let zend: Float = 10
        
        let tolerance:Float = 0.001 // float drift compensation
        
        iterate3D( xstart, w * 1.2, { $0 < xend + tolerance } ,
                   ystart, h * 1.2, { $0 < yend + tolerance } ,
                   zstart, l * 1.2, { $0 < zend + tolerance } ,
                   {
                    x,y,z in
                    self.addTile(x,y,z,
                                 w,h,l)
                    return true
                   } )
    }

This generates a group of blocks or tiles in my Apple TV app (under construction)
like the one you can see in the image “Cloinckz” on my website www.tedvg.com <http://www.tedvg.com/>.

I also prefer the one dimensional iterate(.. too above the for;; or stride()

One could extend these iterator…() functions by adding closures for pre and post iteration handling,
like for printing headers and footers before and/or after a complete [inner] iteration.

Note that breaking with *return false* -which is equivalent to the “break” stmt in
a classical for;; - does not only leave a nested iteration, but also the outer ones.
(maybe a TODO to make individual level- break possible) As it is now, If one
wants to break at the deep iteration level, then one should nest this using 1D iterators.

Anyway, this is just a thought starting to think about multi-dimensional iterators,
and other (encapsulation?) of multi dimensional data as well.
In any case for 2D because table data is used very frequently in many apps. as
most data are in tables.

You won’t believe this :o) but in a sense I might not make so much fuzz anymore
to keep the for;; as this proves to me that I can solve things much better that I thought.
So, I have to rethink this.

Kind Regards
Ted
www.ravelnotes.com <http://www.ravelnotes.com/>

On 31.07.2016, at 18:33, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

I'm replying on Swift-Users and bcc'ing in Swift-Evolution to comply with the core team's request to focus SE on the current mission statement.

At some point soon, Russ Bishop's PR https://github.com/apple/swift/pull/3600 will be incorporated into Swift 3. This PR adds `prefix(while:)` and `drop(while:)` to finish implementing SE-0045. Once that's done, you can combine `sequence(first:, next:)` and `prefix(while:)` to into a single function `sequence(first:, next:, while:)` like this:

public func sequence<T>(first: T, next: (T) -> T?, while test: (T) -> Bool) -> UnfoldSequence<T, UnfoldSequence<T, (T?, Bool)>> {
    return sequence(first: first, next: next).prefix(while: test)
}

The combined sequence/prefix call allows you to create loops like this:

for outerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <= 64 }) {
    for innerIndex in sequence(first: 1, next: { $0 * 2 }, while: { $0 <= 64 }) {
        print(outerIndex, innerIndex)
    }
}

These loops can be nested. break and continue work. You can use tuples for multiple arguments. While I'd like to see a combined form adopted into Swift 4b (the deferred "sugar"), it isn't a high priority.

-- E

On Jul 31, 2016, at 7:18 AM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 31.07.2016, at 04:28, jaden.geller@gmail.com <mailto:jaden.geller@gmail.com> wrote:

What benefit do Iterator2D and Iterator3D provide that nesting does not?

Hi Jaden,
well, simply because of hiding/enclosing repetitive functionality
like with every other programming element is convenient,
prevents errors and from writing the same over and over again.
That is why there are functions.
but you already know that, of course.
Kind Regards
TedvG

On Jul 30, 2016, at 1:48 PM, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi Chris,

thanks for the tip about Hirundo app!

A positive side-effect of removing the classical for;; loop
(yes, it’s me saying this :o) is that it forces me to find
a good and generic equivalent for it,
making the conversion of my for;;s to 3.0 easier.
which is *not* based on collections or sequences and
does not rely on deeper calls to Sequence etc.

so, I’ve made the functions [iterator, iterator2D, iterator3D] (hereunder)
wich btw clearly demonstrate the power and flexibility of Swift.

Very straightforward, and efficient (i assume) just like the classical for;; loop.
It works quite well in my sources.

As a spin-off, I’ve extended these to iterators for matrices 2D and cubes? 3D...

Question:
Perhaps implementing “multi dimensional iterator functions
in Swift might be a good idea. so that is no longer necessary to nest/nest/nest iterators.

Met vriendelijke groeten, sorry for my “intensity” in discussing the classical for;;
I'll have to rethink this for;; again..
Thanks, Ted.

Any remarks ( all ), suggestions about the code hereunder: ?

protocol NumericType
{
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
}

extension Double : NumericType { }
extension Float : NumericType { }
extension CGFloat: NumericType { }
extension Int : NumericType { }
extension Int8 : NumericType { }
extension Int16 : NumericType { }
extension Int32 : NumericType { }
extension Int64 : NumericType { }
extension UInt : NumericType { }
extension UInt8 : NumericType { }
extension UInt16 : NumericType { }
extension UInt32 : NumericType { }
extension UInt64 : NumericType { }

/// Simple iterator with generic parameters, with just a few lines of code.
/// for most numeric types (see above)
/// Usage Example:
///
/// iterate(xmax, { $0 > xmin}, -xstep,
/// {x in
/// print("x = \(x)")
/// return true // returning false acts like a break
/// } )
///
/// -Parameter vstart: Initial value
/// -Parameter step: The iteration stepping value.
/// -Parameter test: A block with iteration test. e.g. {$0 > 10}
///
/// -Parameter block: A block to be executed with each step.
/// The block must include a return true (acts like "continue")
/// or false (acts like "break")
/// -Please Note:
/// There is minor precision loss ca: 1/1000 ... 1/500
/// when iterating with floating point numbers.
/// However, in most cases this can be safely ignored.
/// made by ted van gaalen.

func iterate<T:NumericType> (
                    vstart: T,
                   _ vstep: T,
                   _ test: (T) -> Bool,
                   _ block: (T) -> Bool )
{
    var current = vstart
    
    while test(current) && block(current)
    {
        current = current + vstep
    }
}

/// X,Y 2D matrix (table) iterator with generic parameters
func iterate2D<T:NumericType> (
     xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
   _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
   _ block: (T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            dontStop = block(xcurrent, ycurrent)
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

/// X,Y,Z 3D (cubic) iterator with generic parameters:

func iterate3D<T:NumericType> (
    xstart: T, _ xstep: T, _ xtest: (T) -> Bool,
  _ ystart: T, _ ystep: T, _ ytest: (T) -> Bool,
  _ zstart: T, _ zstep: T, _ ztest: (T) -> Bool,
      _ block: (T,T,T) -> Bool )
{
    var xcurrent = xstart
    var ycurrent = ystart
    var zcurrent = zstart
    
    var dontStop = true
    
    while xtest(xcurrent) && dontStop
    {
        ycurrent = ystart
        while ytest(ycurrent) && dontStop
        {
            zcurrent = zstart
            while ztest(zcurrent) && dontStop
            {
                dontStop = block(xcurrent, ycurrent, zcurrent)
                zcurrent = zcurrent + zstep
            }
            ycurrent = ycurrent + ystep
        }
        xcurrent = xcurrent + xstep
    }
}

func testIterator()
{
    iterate(0.0, 0.5, {$0 < 1000.00000} ,
            { value in
                print("Value = \(value) ")
                return true
    } )

    let startv: CGFloat = -20.0
    let stepv: CGFloat = 0.5
    
    iterate(startv, stepv, {$0 < 1000.00000} ,
            { val in
                print("R = \(val)")
                return true
    } )

    let tolerance = 0.01 // boundary tolerance for floating point type
    
    iterate2D( 0.0, 10.0, { $0 < 100.0 + tolerance } ,
               0.0, 5.0, { $0 < 50.0 + tolerance } ,
               {x,y in
                print("x = \(x) y = \(y)")
                return true // false from block stops iterating ( like break)
                } )

    iterate3D( 0.0, 10.0, { $0 < 30.0 } , // x
               0.0, 5.0, { $0 < 20.0 } , // y
               10.0, -5.0, { $0 > -10.0 } , // z
               {x,y,z in
                    print("x = \(x) y = \(y) z = \(z)")
                    if z < 0.0
                    {
                        print ( "** z value \(z) is below zero! **" )
                        
                        return false // (acts as break in for;:wink:
                    }
                    return true // return stmt is obligatory (continue)
               } )
}

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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