假设我想在数组上映射一个函数,但该函数的类型不仅是
a -> b
,而是a -> Int -> b
,也就是说该函数还需要一个索引。我该怎么做呢?简短回答,使用traverse
。
更长的例子:
import qualified Data.Array.Repa as A
import qualified Data.Vector.Unboxed as U
arr1 :: A.Array A.DIM2 Double
arr1 = A.fromVector (A.Z A.:. 2 A.:. 3) $ U.fromList [1::Double,2,3,4,5,6]
arr2 :: A.Array A.DIM2 Double
arr2 = A.traverse arr1 id (\lf i@(A.Z A.:. r A.:. c) ->
(lf i) + (fromIntegral r) + (fromIntegral c))
arr1
是一个 2x3 的矩阵。 traverse
是一个函数,它接受三个参数:(1) 原始数组,(2) 将源索引映射到目标索引的函数,以及 (3) 一个函数,该函数给出了 (i) 原始数组的查找函数和 (ii) 返回新值的索引。
因此,在这里,arr2
通过添加该特定条目的行和列索引来修改每个原始元素。
很好的问题,在Repa教程中没有记录,因此我已经更新了一个新的遍历章节。
特别是,traverse
可以让你:
这意味着你可以做到像这样的事情:
用它们的行索引替换所有元素
> traverse a id (\_ (Z :. i :. j :. k) -> i)
[0,0,0,0,0,0,0,0,0
,1,1,1,1,1,1,1,1,1
,2,2,2,2,2,2,2,2,2]
将元素乘以其所在的行
> traverse a id (\f (Z :. i :. j :. k) -> f (Z :. i :. j :. k) * i)
[0,0,0,0,0,0,0,0,0
,10,11,12,13,14,15,16,17,18
,38,40,42,44,46,48,50,52,54]
等等。 travese
非常强大,而且还可以神奇地并行。
高级:并行图像去色
使用zipWith
zipWith (\idx ele -> if even idx then div ele 2 else ele) [0..] xs