使用函数值生成新序列

时间:2018-11-28 13:05:36

标签: mapping nim

按照标题,我有以下代码:

proc squared(n: int64): int64 = n * n

echo squared(5)

产生以下输出:

25

但是,如果我知道要使用squared填充一个序列,我会写一些类似的东西:

import sequtils

proc squared_seq(n: int64): seq[int64] =
    result = newSeq[int64](n)
    for i in 0 ..< n:
        result[i] = squared(i)

echo squared_seq(5)

我希望这会产生以下输出:

@[0, 1, 4, 9, 16]

但是我得到的只是以下错误(在result[i] = ...行上):

Error: type mismatch: got <seq[int64], int64, int64>
but expected one of: 
proc `[]=`(s: var string; i: BackwardsIndex; x: char)
proc `[]=`[T, U](s: var string; x: HSlice[T, U]; b: string)
proc `[]=`[T](s: var openArray[T]; i: BackwardsIndex; x: T)
proc `[]=`[Idx, T, U, V](a: var array[Idx, T]; x: HSlice[U, V]; b: openArray[T])
template `[]=`(s: string; i: int; val: char)
proc `[]=`[I: Ordinal; T, S](a: T; i: I; x: S)
proc `[]=`[T, U, V](s: var seq[T]; x: HSlice[U, V]; b: openArray[T])
proc `[]=`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T)

最终,这是某种形式的映射,因此我认为这段代码可以工作:

var arr = toSeq(0 ..< 5)
var sq_arr = map(arr, squared)

echo sq_arr

具有与以前相同的预期输出:

@[0, 1, 4, 9, 16]

但是我却得到了(在map行上):

Error: type mismatch: got <seq[int], proc (n: int64): int64{.noSideEffect, gcsafe, locks: 0.}>
but expected one of: 
proc map[T](s: var openArray[T]; op: proc (x: var T) {.closure.})
first type mismatch at position: 2
required type: proc (x: var T){.closure.}
but expression 'squared' is of type: proc (n: int64): int64{.noSideEffect, gcsafe, locks: 0.}
proc map[T, S](s: openArray[T]; op: proc (x: T): S {.closure.}): seq[S]
first type mismatch at position: 2
required type: proc (x: T): S{.closure.}
but expression 'squared' is of type: proc (n: int64): int64{.noSideEffect, gcsafe, locks: 0.}

我在做什么错了?

(我使用的是Nim 0.19.0,但也不适用于Nim 0.18.0)。

2 个答案:

答案 0 :(得分:1)

发生错误是因为您试图使用int64来索引result序列。使用通用的int平台类型(depending on your platform可以是32位长或64位)来访问序列。您可以将squared_seq参数更改为int,它应该可以编译:

import sequtils

proc squared(n: int64): int64 = n * n

proc squared_seq(n: int): seq[int64] =
    result = newSeq[int64](n)
    for i in 0 ..< n:
        result[i] = squared(i)

echo squared_seq(5)

或者,您可以像int64一样投射for i in 0 ..< int(n),但这可能很危险,具体取决于传递给proc的值。

答案 1 :(得分:1)

(感谢freenode中#nim的@ leorize,@ mratsim和@ alehander42)。

第一个解决方案的问题是seq的索引必须为int,并且int64int的转换不是自动的。 由于int的签名所要求的int64squared是自动的,因此类似以下的事情会起作用。

import sequtils

proc squared_seq(n: int64): seq[int64] =
    result = newSeq[int64](n)
    for i in 0 ..< int(n):
        result[i] = squared(i)

或者,以下方法也可以工作:

proc squared_seq(n: int64): seq[int64] =
    result = newSeq[int64](n)
    for i in 0 ..< n:
        result[int(i)] = squared(i)

但是,我不太确定,如果以后仅支持result = newSeq[int64](n)索引,为什么n不需要intint。 不过,这似乎是一个不需要的功能。

关于映射方法,这里的问题是输入类型为int,而squared()需要int64。在这种情况下,显然最好的方法是对intint64序列使用某种代理方式,例如:

var arr = toSeq(0 ..< 5)
var sq_arr = map(arr, proc(x: int): int64 = squared(x))

或者更好的是,强制toSeq产生int64,例如:

var arr = toSeq(0'i64 ..< 5'i64)
var sq_arr = map(arr, squared)

或更妙的是,使用map的类型松弛版本,即mapIt

var arr = toSeq(0 ..< 5)
var sq_arr = mapIt(arr, squared(it))

这还会产生更快的代码。