Nim: List comprehensions do not work with generic parameter

Created on 14 Apr 2017  路  11Comments  路  Source: nim-lang/Nim

This compiles:

proc foo: seq[int] = 
    return lc[x | (x <- 1..10, x mod 2 == 0), int]

This doesn't

proc foo[T]: seq[int] = 
    return lc[x | (x <- 1..10, x mod 2 == 0), int]

Error: undeclared identifier: '|'

High Priority Language design Stdlib

Most helpful comment

I think in the long run we want to obsolete this macro and allow a for loop as an expression.

All 11 comments

This is stdlib problem, the language works as expected here. The following compiles:

import future

proc foo[T]: seq[int] =
  mixin `|`, x, `<-`
  return lc[x | (x <- 1..10, x mod 2 == 0), int]

The lc macro needs to be redesigned.

Not sure if my comment is out of place, but I encourage fixing this. I was trying to write an iterator over combinations (like the one in Python's itertools module) and I encountered this problem. It would be nice if I were able to use lc with generics in this case.

In addition to this: IMO, and I think @Araq agrees, the list comprehensions should be made more Pythonic.

I think in the long run we want to obsolete this macro and allow a for loop as an expression.

High priority because we need to make a decision (if we decide to remove then this will be a breaking change)

I don't understand the difference between the following two cases:

This one doesn't compile:

proc dist(bc1, bc2: string): int {.inline.} =
  mixin `|`, `<-`  # Error: invalid expression: 'mixin `|`, `<-`'
  sum(lc[int(pair.a != pair.b) | (pair <- zip(bc1, bc2))])

This one does:

  proc matchToAllowed(fastq: Fastq): (string, string) =
    let bcSeq = fastq[1][(bcStart-1)..<(bcStart + bcLen - 1)]
    let bcQuals = fastq[2][(bcStart-1)..<(bcStart + bcLen - 1)]
    let bcProbs = nucProbs(bcSeq, bcQuals)
    proc likelihood(barcode: string): float =
      var letter: char
      var errProb: float
      result = 1
      for i, np in bcProbs.pairs():
        (letter, errProb) = np
        if letter == barcode[i]:
          result = result * (1 - errProb)
        else:
          result = result * (errProb / 3)
    mixin `|`, `<-`  # No problem here
    let likelihoods = lc[likelihood(allowed) | (allowed <- barcodes), float]
    var maxLike = likelihoods[0]
    var bestIdx = 0
    # https://stackoverflow.com/a/48123056/1878788
    for idx, like in likelihoods:
      if like > maxLike:
        maxLike = like
        bestIdx = idx
    let candidate = barcodes[bestIdx]
    let theDist = dist(bcSeq, candidate)
    let annot = join([
      candidate,
      formatFloat(maxLike, ffScientific),
      theDist.intToStr], ":")
    if theDist > maxDiff:
      result = ("Undetermined", annot)
    else:
      result = (candidate, annot)

I have import future in both cases.

mixin is only valid in a generic proc or a template.

@Araq It doesn't seem to me that my second example is generic, or is a template. Did I miss something?

Ran the code in the OP on current devel https://github.com/nim-lang/Nim/commit/91b37311d9974ae30745946a52c9a971da1616f4 and it works fine now.

Ran the code in the OP on current devel 91b3731 and it works fine now.

Can confirm for 0.19.

I think in the long run we want to obsolete this macro and allow a for loop as an expression.

We now have for-loop macros.

Can we close this one?

Can we close this one?

Requires a test case.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

juancarlospaco picture juancarlospaco  路  3Comments

Tronic picture Tronic  路  3Comments

zzz125 picture zzz125  路  4Comments

teroz picture teroz  路  3Comments

alaviss picture alaviss  路  3Comments