diff options
author | Hans Raaf <hara@oderwat.de> | 2016-03-05 16:45:32 +0100 |
---|---|---|
committer | Hans Raaf <hara@oderwat.de> | 2016-03-06 17:52:18 +0100 |
commit | cddabcfc63b0643a5c5ba0d065b5f502263dec78 (patch) | |
tree | 200cd3b5db2a5e5d5f894d671dca82f400c8b3d3 | |
parent | e4e8ebd4a50bc86b0b08df449d5ff72e365a4c6a (diff) | |
download | Nim-cddabcfc63b0643a5c5ba0d065b5f502263dec78.tar.gz |
Fixes foldl() and foldr() + foldl() with start parameter.
This fixes the (potential) multi-evaluation of the sequence parameter in foldl() and foldr(). It also adds a foldl() version which gets a start parameter. This allows for creating a result with a different type than the elements of the sequence.
-rw-r--r-- | lib/pure/collections/sequtils.nim | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index b72face91..0e3824a81 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -508,13 +508,39 @@ template foldl*(sequence, operation: expr): expr = ## assert subtraction == -15, "Subtraction is (((5)-9)-11)" ## assert multiplication == 495, "Multiplication is (((5)*9)*11)" ## assert concatenation == "nimiscool" - assert sequence.len > 0, "Can't fold empty sequences" - var result {.gensym.}: type(sequence[0]) - result = sequence[0] - for i in 1..<sequence.len: + let s = sequence + assert s.len > 0, "Can't fold empty sequences" + var result {.gensym.}: type(s[0]) + result = s[0] + for i in 1..<s.len: let a {.inject.} = result - b {.inject.} = sequence[i] + b {.inject.} = s[i] + result = operation + result + +template foldl*(sequence, operation: expr, first): expr = + ## Template to fold a sequence from left to right, returning the accumulation. + ## + ## This version of ``foldl`` gets a starting parameter. This makes it possible + ## to accumulate the sequence into a different type than the sequence elements. + ## + ## The ``operation`` parameter should be an expression which uses the variables + ## ``a`` and ``b`` for each step of the fold. The ``first`` parameter is the + ## start value (the first ``a``) and therefor defines the type of the result. + ## Example: + ## + ## .. code-block:: + ## let + ## numbers = @[0, 8, 1, 5] + ## digits = foldl(numbers, a & (chr(b + ord('0'))), "") + ## assert digits == "0815" + var result {.gensym.}: type(first) + result = first + for x in items(sequence): + let + a {.inject.} = result + b {.inject.} = x result = operation result @@ -544,12 +570,13 @@ template foldr*(sequence, operation: expr): expr = ## assert subtraction == 7, "Subtraction is (5-(9-(11)))" ## assert multiplication == 495, "Multiplication is (5*(9*(11)))" ## assert concatenation == "nimiscool" - assert sequence.len > 0, "Can't fold empty sequences" - var result {.gensym.}: type(sequence[0]) - result = sequence[sequence.len - 1] - for i in countdown(sequence.len - 2, 0): + let s = sequence + assert s.len > 0, "Can't fold empty sequences" + var result {.gensym.}: type(s[0]) + result = sequence[s.len - 1] + for i in countdown(s.len - 2, 0): let - a {.inject.} = sequence[i] + a {.inject.} = s[i] b {.inject.} = result result = operation result |