#arrays #haskell #repa
#массивы #haskell #repa
Вопрос:
Представьте, что я хочу отобразить функцию поверх массива, но функция имеет тип не только a -> b
но a -> Int -> b
, т.е. функция также принимает индекс. Как мне это сделать?
Ответ №1:
Короткий ответ, используйте 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
представляет собой матрицу 2х3. traverse
— это функция, которая принимает (1) исходный массив, (2) функцию для сопоставления исходных индексов с целевыми индексами и (3) функцию, которой присваивается (i) функция поиска в исходном массиве и (ii) индекс, который возвращает новое значение.
Итак, здесь arr2
изменяется каждый из исходных элементов путем добавления индексов строк и столбцов этой конкретной записи.
Ответ №2:
Хороший вопрос, и он не был задокументирован в руководстве по 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
это очень мощный, а также волшебным образом параллельный.
Дополнительно: параллельная десатурация изображения
Ответ №3:
Используйте zipWith
zipWith (idx ele -> if even idx then div ele 2 else ele) [0..] xs