Proposal: for loops with return values


(Amir Michail) #1

These would be like the unrolled versions of Python’s generator expressions.

Examples:

let a:[Int] = for x in l { yield x*2 }

let b:[(Int,Int)] = for row in 0..<m { for col in 0..<n { yield (row,col) } }

let c:[(Int,Int)] = for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }


(Félix Cloutier) #2

This has been proposed before and Chris said that it would be out of scope for Swift 3. There is definitely interest in this area though.

Félix

···

Le 14 janv. 2016 à 15:30:07, Amir Michail via swift-evolution <swift-evolution@swift.org> a écrit :

These would be like the unrolled versions of Python’s generator expressions.

Examples:

let a:[Int] = for x in l { yield x*2 }

let b:[(Int,Int)] = for row in 0..<m { for col in 0..<n { yield (row,col) } }

let c:[(Int,Int)] = for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

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


(Craig Cruden) #3

I believe this is the same as Scala’s for-comprehension….. and Scala’s for-comprehension is actually just syntactic sugar for a combination of flatMap, map and withFilter.

Although harder to read for many… it likely could be written similarly in Swift.

i.e.

for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

in Scala is

for {
   row <- 0 to m
   col <- 0 to n
   if row+col < 5
} yield (row, col)

which is actually (after the compiler is done with it):

(0 to m).flatMap(x => (0 to n).withFilter(y => x + y < 5).map(y => (x, y)))

I have not tried to do it in the playground but I would expect since I believe all the functions are available in Swift.

Note: 0 to m // is a range in Scala
  withFilter is a filter which does not copy the contents of what it is filtering…. it is just applying the filter as needed when mapping.

···

On 2016-01-15, at 3:35:23, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

This has been proposed before and Chris said that it would be out of scope for Swift 3. There is definitely interest in this area though.

Félix

Le 14 janv. 2016 à 15:30:07, Amir Michail via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

These would be like the unrolled versions of Python’s generator expressions.

Examples:

let a:[Int] = for x in l { yield x*2 }

let b:[(Int,Int)] = for row in 0..<m { for col in 0..<n { yield (row,col) } }

let c:[(Int,Int)] = for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

_______________________________________________
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


(Thorsten Seitz) #4

Scala’s for-comprehensions are very powerful, precisely because they are using flatMap etc.
This allows using them with other types instead of collections, e.g. asynchronous calls:

func someAsyncCall() -> Future<Int> { … }
func someOtherAsyncCall() -> Future<Int> { … }

// mixing Scala and Swift syntax here...
let z: Future<Int> = for {
  x <- someAsyncCall()
  y <- someOtherAsyncCall()
} yield (x + y)

The important thing for this to look nice is that there is no nesting like in your Swift example. Otherwise you get a pyramid of doom (think of more async calls).

Basically it is the same as Haskell’s do notation and you can do powerful things with that like the async example. Another nice example is the abstraction of Bayes’ rules presented in this blog: http://www.randomhacks.net/2007/02/22/bayes-rule-and-drug-tests/

-Thorsten

···

Am 14.01.2016 um 22:10 schrieb Craig Cruden via swift-evolution <swift-evolution@swift.org>:

I believe this is the same as Scala’s for-comprehension….. and Scala’s for-comprehension is actually just syntactic sugar for a combination of flatMap, map and withFilter.

Although harder to read for many… it likely could be written similarly in Swift.

i.e.

for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

in Scala is

for {
   row <- 0 to m
   col <- 0 to n
   if row+col < 5
} yield (row, col)

which is actually (after the compiler is done with it):

(0 to m).flatMap(x => (0 to n).withFilter(y => x + y < 5).map(y => (x, y)))

I have not tried to do it in the playground but I would expect since I believe all the functions are available in Swift.

Note: 0 to m // is a range in Scala
  withFilter is a filter which does not copy the contents of what it is filtering…. it is just applying the filter as needed when mapping.

On 2016-01-15, at 3:35:23, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This has been proposed before and Chris said that it would be out of scope for Swift 3. There is definitely interest in this area though.

Félix

Le 14 janv. 2016 à 15:30:07, Amir Michail via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

These would be like the unrolled versions of Python’s generator expressions.

Examples:

let a:[Int] = for x in l { yield x*2 }

let b:[(Int,Int)] = for row in 0..<m { for col in 0..<n { yield (row,col) } }

let c:[(Int,Int)] = for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

_______________________________________________
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-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Craig Cruden) #5

What is the most readable/concise (balance) for writing something like the following in swift:

val host: Option[String] = Some("host")
val port: Option[Int] = Some(80)
val addr = for {
  h <- host
  p <- port
} yield new InetSocketAddress(h, p)

i.e. If either of the optionals is None then the result will be None otherwise it will be Some(inetSocketAddress).

···

On 2016-01-15, at 5:57:33, Thorsten Seitz <tseitz42@icloud.com> wrote:

Scala’s for-comprehensions are very powerful, precisely because they are using flatMap etc.
This allows using them with other types instead of collections, e.g. asynchronous calls:

func someAsyncCall() -> Future<Int> { … }
func someOtherAsyncCall() -> Future<Int> { … }

// mixing Scala and Swift syntax here...
let z: Future<Int> = for {
  x <- someAsyncCall()
  y <- someOtherAsyncCall()
} yield (x + y)

The important thing for this to look nice is that there is no nesting like in your Swift example. Otherwise you get a pyramid of doom (think of more async calls).

Basically it is the same as Haskell’s do notation and you can do powerful things with that like the async example. Another nice example is the abstraction of Bayes’ rules presented in this blog: http://www.randomhacks.net/2007/02/22/bayes-rule-and-drug-tests/

-Thorsten

Am 14.01.2016 um 22:10 schrieb Craig Cruden via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

I believe this is the same as Scala’s for-comprehension….. and Scala’s for-comprehension is actually just syntactic sugar for a combination of flatMap, map and withFilter.

Although harder to read for many… it likely could be written similarly in Swift.

i.e.

for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

in Scala is

for {
   row <- 0 to m
   col <- 0 to n
   if row+col < 5
} yield (row, col)

which is actually (after the compiler is done with it):

(0 to m).flatMap(x => (0 to n).withFilter(y => x + y < 5).map(y => (x, y)))

I have not tried to do it in the playground but I would expect since I believe all the functions are available in Swift.

Note: 0 to m // is a range in Scala
  withFilter is a filter which does not copy the contents of what it is filtering…. it is just applying the filter as needed when mapping.

On 2016-01-15, at 3:35:23, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This has been proposed before and Chris said that it would be out of scope for Swift 3. There is definitely interest in this area though.

Félix

Le 14 janv. 2016 à 15:30:07, Amir Michail via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

These would be like the unrolled versions of Python’s generator expressions.

Examples:

let a:[Int] = for x in l { yield x*2 }

let b:[(Int,Int)] = for row in 0..<m { for col in 0..<n { yield (row,col) } }

let c:[(Int,Int)] = for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

_______________________________________________
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-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Amir Michail) #6

What is the most readable/concise (balance) for writing something like the following in swift:

val host: Option[String] = Some("host")
val port: Option[Int] = Some(80)
val addr = for {
  h <- host
  p <- port
} yield new InetSocketAddress(h, p)

Wouldn’t “let/val { ...” be better than “for { ...” in this context?

···

On Jan 19, 2016, at 7:26 AM, Craig Cruden <ccruden@novafore.com> wrote:

i.e. If either of the optionals is None then the result will be None otherwise it will be Some(inetSocketAddress).

On 2016-01-15, at 5:57:33, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Scala’s for-comprehensions are very powerful, precisely because they are using flatMap etc.
This allows using them with other types instead of collections, e.g. asynchronous calls:

func someAsyncCall() -> Future<Int> { … }
func someOtherAsyncCall() -> Future<Int> { … }

// mixing Scala and Swift syntax here...
let z: Future<Int> = for {
  x <- someAsyncCall()
  y <- someOtherAsyncCall()
} yield (x + y)

The important thing for this to look nice is that there is no nesting like in your Swift example. Otherwise you get a pyramid of doom (think of more async calls).

Basically it is the same as Haskell’s do notation and you can do powerful things with that like the async example. Another nice example is the abstraction of Bayes’ rules presented in this blog: http://www.randomhacks.net/2007/02/22/bayes-rule-and-drug-tests/

-Thorsten

Am 14.01.2016 um 22:10 schrieb Craig Cruden via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

I believe this is the same as Scala’s for-comprehension….. and Scala’s for-comprehension is actually just syntactic sugar for a combination of flatMap, map and withFilter.

Although harder to read for many… it likely could be written similarly in Swift.

i.e.

for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

in Scala is

for {
   row <- 0 to m
   col <- 0 to n
   if row+col < 5
} yield (row, col)

which is actually (after the compiler is done with it):

(0 to m).flatMap(x => (0 to n).withFilter(y => x + y < 5).map(y => (x, y)))

I have not tried to do it in the playground but I would expect since I believe all the functions are available in Swift.

Note: 0 to m // is a range in Scala
  withFilter is a filter which does not copy the contents of what it is filtering…. it is just applying the filter as needed when mapping.

On 2016-01-15, at 3:35:23, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This has been proposed before and Chris said that it would be out of scope for Swift 3. There is definitely interest in this area though.

Félix

Le 14 janv. 2016 à 15:30:07, Amir Michail via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

These would be like the unrolled versions of Python’s generator expressions.

Examples:

let a:[Int] = for x in l { yield x*2 }

let b:[(Int,Int)] = for row in 0..<m { for col in 0..<n { yield (row,col) } }

let c:[(Int,Int)] = for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

_______________________________________________
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-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Craig Cruden) #7

I don’t know - the syntax you gave me won’t run in the playground…..

the for-comprehension aka “list comprehension” (or in this case optional comprehension) is from Scala.

I was wondering if there was an easy way to state the same with optionals in Swift.

I hesitate to paste in my solution since there is likely a more reasonable way to chain optionals that would effectively do the same as for-comprehension of optionals in Scala (different language, different ways of approaching things).

···

On 2016-01-19, at 21:20:21, Amir Michail <a.michail@me.com> wrote:

On Jan 19, 2016, at 7:26 AM, Craig Cruden <ccruden@novafore.com <mailto:ccruden@novafore.com>> wrote:

What is the most readable/concise (balance) for writing something like the following in swift:

val host: Option[String] = Some("host")
val port: Option[Int] = Some(80)
val addr = for {
  h <- host
  p <- port
} yield new InetSocketAddress(h, p)

Wouldn’t “let/val { ...” be better than “for { ...” in this context?

i.e. If either of the optionals is None then the result will be None otherwise it will be Some(inetSocketAddress).

On 2016-01-15, at 5:57:33, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Scala’s for-comprehensions are very powerful, precisely because they are using flatMap etc.
This allows using them with other types instead of collections, e.g. asynchronous calls:

func someAsyncCall() -> Future<Int> { … }
func someOtherAsyncCall() -> Future<Int> { … }

// mixing Scala and Swift syntax here...
let z: Future<Int> = for {
  x <- someAsyncCall()
  y <- someOtherAsyncCall()
} yield (x + y)

The important thing for this to look nice is that there is no nesting like in your Swift example. Otherwise you get a pyramid of doom (think of more async calls).

Basically it is the same as Haskell’s do notation and you can do powerful things with that like the async example. Another nice example is the abstraction of Bayes’ rules presented in this blog: http://www.randomhacks.net/2007/02/22/bayes-rule-and-drug-tests/

-Thorsten

Am 14.01.2016 um 22:10 schrieb Craig Cruden via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

I believe this is the same as Scala’s for-comprehension….. and Scala’s for-comprehension is actually just syntactic sugar for a combination of flatMap, map and withFilter.

Although harder to read for many… it likely could be written similarly in Swift.

i.e.

for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

in Scala is

for {
   row <- 0 to m
   col <- 0 to n
   if row+col < 5
} yield (row, col)

which is actually (after the compiler is done with it):

(0 to m).flatMap(x => (0 to n).withFilter(y => x + y < 5).map(y => (x, y)))

I have not tried to do it in the playground but I would expect since I believe all the functions are available in Swift.

Note: 0 to m // is a range in Scala
  withFilter is a filter which does not copy the contents of what it is filtering…. it is just applying the filter as needed when mapping.

On 2016-01-15, at 3:35:23, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This has been proposed before and Chris said that it would be out of scope for Swift 3. There is definitely interest in this area though.

Félix

Le 14 janv. 2016 à 15:30:07, Amir Michail via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

These would be like the unrolled versions of Python’s generator expressions.

Examples:

let a:[Int] = for x in l { yield x*2 }

let b:[(Int,Int)] = for row in 0..<m { for col in 0..<n { yield (row,col) } }

let c:[(Int,Int)] = for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

_______________________________________________
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-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Craig Cruden) #8

i.e. the Swift way of doing things that comes to mind (equivalent) would be:

let host: String? = “host”
let port: Int? = “80”

let inetAddress = InetSocketAddress?
if let host = host, port = port {
  inetAddress = InetSocketAddress(host, port)
}
else {
  inetAddress = nil
}

Just wondering if there was a cleaner way - because to me that just looks ugly.

(or the map/flatmap route which would probably not be immediately understandable to some)

···

On 2016-01-19, at 21:20:21, Amir Michail <a.michail@me.com> wrote:

On Jan 19, 2016, at 7:26 AM, Craig Cruden <ccruden@novafore.com <mailto:ccruden@novafore.com>> wrote:

What is the most readable/concise (balance) for writing something like the following in swift:

val host: Option[String] = Some("host")
val port: Option[Int] = Some(80)
val addr = for {
  h <- host
  p <- port
} yield new InetSocketAddress(h, p)

Wouldn’t “let/val { ...” be better than “for { ...” in this context?

i.e. If either of the optionals is None then the result will be None otherwise it will be Some(inetSocketAddress).

On 2016-01-15, at 5:57:33, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Scala’s for-comprehensions are very powerful, precisely because they are using flatMap etc.
This allows using them with other types instead of collections, e.g. asynchronous calls:

func someAsyncCall() -> Future<Int> { … }
func someOtherAsyncCall() -> Future<Int> { … }

// mixing Scala and Swift syntax here...
let z: Future<Int> = for {
  x <- someAsyncCall()
  y <- someOtherAsyncCall()
} yield (x + y)

The important thing for this to look nice is that there is no nesting like in your Swift example. Otherwise you get a pyramid of doom (think of more async calls).

Basically it is the same as Haskell’s do notation and you can do powerful things with that like the async example. Another nice example is the abstraction of Bayes’ rules presented in this blog: http://www.randomhacks.net/2007/02/22/bayes-rule-and-drug-tests/

-Thorsten

Am 14.01.2016 um 22:10 schrieb Craig Cruden via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

I believe this is the same as Scala’s for-comprehension….. and Scala’s for-comprehension is actually just syntactic sugar for a combination of flatMap, map and withFilter.

Although harder to read for many… it likely could be written similarly in Swift.

i.e.

for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

in Scala is

for {
   row <- 0 to m
   col <- 0 to n
   if row+col < 5
} yield (row, col)

which is actually (after the compiler is done with it):

(0 to m).flatMap(x => (0 to n).withFilter(y => x + y < 5).map(y => (x, y)))

I have not tried to do it in the playground but I would expect since I believe all the functions are available in Swift.

Note: 0 to m // is a range in Scala
  withFilter is a filter which does not copy the contents of what it is filtering…. it is just applying the filter as needed when mapping.

On 2016-01-15, at 3:35:23, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This has been proposed before and Chris said that it would be out of scope for Swift 3. There is definitely interest in this area though.

Félix

Le 14 janv. 2016 à 15:30:07, Amir Michail via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

These would be like the unrolled versions of Python’s generator expressions.

Examples:

let a:[Int] = for x in l { yield x*2 }

let b:[(Int,Int)] = for row in 0..<m { for col in 0..<n { yield (row,col) } }

let c:[(Int,Int)] = for row in 0..<m { for col in 0..<n where row+col < 5 { yield (row,col) } }

_______________________________________________
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-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Jim Dovey) #9

You can always wrap it in a (nicely inline-able) function for cleanliness:

func makeAddr(host: String?, port: Int?) -> InetSocketAddress? {
  guard let h = host, p = port else { return nil }
  return InetSocketAddress(host: h, port: p)
}

// … somewhere else …
let host: String? = getHost()
let port: Int? = getPort()

guard let inetAddress = makeAddr(host, port) else { throw SocketError(EADDR) }

Cheers,
-Jim

···

On Jan 19, 2016, at 7:08 AM, Craig Cruden via swift-evolution <swift-evolution@swift.org> wrote:

i.e. the Swift way of doing things that comes to mind (equivalent) would be:

let host: String? = “host”
let port: Int? = “80”

let inetAddress = InetSocketAddress?
if let host = host, port = port {
  inetAddress = InetSocketAddress(host, port)
}
else {
  inetAddress = nil
}

Just wondering if there was a cleaner way - because to me that just looks ugly.