Before we begin: I'm new to Nim and it's been a while since I did anything to
do with AST, parsing, etc. so my suggestions may be whacky. If they are, simply
say so and turn the discussion in the right direction.
**Where we're at**
List comprehension is currently available through the _future_ module. For
loops as expressions have been suggested to replace it but what should their
capabilities be, and what should the syntax look like?
**Requirements**
Should the syntax be:
* 1) Familiar to anyone knowing math/Python? (e.g., x for x in y [if z])
* 2) Similar to for statements? (e.g., for x in y: [if z:] x)
_(The pros and cons of each are probably best found by providing examples of
each.)_
Should it be capable of:
* A) Creating only seq[T]? (So, sequence comprehension)
* B) Creating any type Y[T] implementing add()? (Basically, [mutable]
collection comprehension)
_(I'm guessing B, since expressiveness is a higher priority than elegance.)_
Assuming B, should the type be denoted:
* X) Through constructors? (Araq mentioned this but I'm not sure I understood
correctly)
* Y) Only for types other than seq? (i.e., the type is seq if it can't be
inferred. I can imagine the AST is built in a way that makes this infeasible or
impossible)
Should it be implemented on parser level, as a macro, or something else? I'm
not very familiar with the any of these things, but it I'm guessing they put
different limitations on the syntax and provide varying levels of efficiency.
For Y, this is what I had in mind:
# @[2, 3, 4]
var a = for x in [1, 2, 3]: x+1
# {2, 3, 4}
var a: set[int] = for x in [1, 2, 3]: x+1
# With input "A", "B", "C": {"A", "B", "C"} and @["A", "B", "C"]
# With input "A", "A", "C": {"A", "C"} and @["A", "A", "C"]
var a: set[string] = for x in 1..3: readLine(stdin)
var a = for x in 1..3: readLine(stdin)
And lastly, here's a wall of code that contains my not-so-well-structured notes:
import strutils, algorithm, math
var bowlSizes = (var s: seq[int] = @[]; for _ in 1..3:
s.add(parseInt(readLine(stdin))); s)
# var bowlSizes = lc[parseInt(readLine(stdin)) | (_ <- 1..3), int]
bowlSizes.sort(system.cmp[int])
echo bowlSizes[1]
"""Syntax suggestions; line one describes the syntax, line two is how it
could be expanded."""
# Syntax 1
var a: seq[T] = for x in y: expr
var a: seq[T] = (var s: seq[T] = seq[T](); for x in y: (var e: T = expr; if
e != nil: s.add(e)); s)
# Syntax 2, rule 1
var a: seq[T] = expr for x in y
var a: seq[T] = (var s: seq[T] = seq[T](); for x in y: (var e: T = expr; if
e != nil: s.add(e)); s)
# Syntax 2, rule 2
var a: seq[T] = expr for x in y cond
var a: seq[T] = (var s: seq[T] = seq[T](); for x in y: (var e: T = expr;
cond: (if e != nil: s.add(e))); s)
"""Random examples"""
# Syntax 1 examples
A) var a: seq[int] = for x in [1, 2, 3, 4]: if x mod 2 == 0: x else: x + 1
# @[2, 2, 4, 4]
B) var a: seq[int] = for x in [1, 2, 3, 4]: if x mod 2 == 0: x # @[2, 4]
C) var a = ... # type inference
D) var a = for x in 0..10: if x mod 2 == 0: (if x < 5: 5 - x else: x - 5)
E1) var a = for x in [1, 2, 3, 4, 5]: for y in [1, 1, 2, 3, 5]: if x mod y
== 0: x / y
E2)
var a =
for x in [1, 2, 3, 4, 5]:
for y in [1, 1, 2, 3, 5]:
if x mod y == 0:
x / y
# Syntax 2 examples
A) var a: seq[int] = x if x mod 2 == 0 else x + 1 for x in [1, 2, 3, 4] #
@[2, 2, 4, 4]
B1) var a: seq[int] = x for x in [1, 2, 3, 4] if x mod 2 == 0 # @[2, 4]
B2) var a: seq[int] = x if x mod 2 == 0 for x in [1, 2, 3, 4] # @[2, 4]
C) var a = ... # type inference
D) var a: seq[int] = 5 - x if x < 5 else x - 5 for x in 0..10 if x mod 2 == 0
E1) var a = x / y for x in [1, 2, 3, 4, 5] for y in [1, 1, 2, 3, 5] if x
mod y == 0
E2)
var a = x / y
for x in [1, 2, 3, 4, 5]
for y in [1, 1, 2, 3, 5]
if x mod y == 0
"""More examples. From
http://www.secnetix.de/olli/Python/list_comprehensions.hawk"""
# Plain math
S = {x^2 : x in {0 ... 9}}
V = (1, 2, 4, 8, ..., 2^12)
M = {x | x in S and x even}
# Python
S = [x**2 for x in range(10)]
V = [2**i for i in range(13)]
M = [x for x in S if x % 2 == 0]
# Syntax 1
var S = for x in 0..9: x^2
var V = for i in 0..12: 2^i
var M = for x in S: if x mod 2 == 0: x
# Syntax 2
var S = x^2 for x in 0..9
var V = 2^i for i in 0..12
var M = x for x in S if x mod 2 == 0
OR var M = x if x mod 2 == 0 for x in S
"""Allow any collection that implements add(). Is it unintuitive or harder
to implement?"""
# Variation of Syntax 1
var a: Y[T] = for x in y: expr
var a: Y[T] = (var s: Y[T] = Y[T](); for x in y: (var e: T = expr; if e !=
nil: s.add(e)); s)
# Assume seq if not specified?
var a = for x in y: expr
var a: seq[T] = ...
# Variation of Syntax 2
var a: Y[T] = expr for x in y
var a: Y[T] = expr for x in y cond
var a: Y[T] = (var s: Y[T] = Y[T](); ...