Haskell repa — сопоставление с индексами

#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 это очень мощный, а также волшебным образом параллельный.

Дополнительно: параллельная десатурация изображения

Пример из руководства по Repa

Ответ №3:

Используйте zipWith

 zipWith (idx ele -> if even idx then div ele 2 else ele) [0..] xs