Я пытаюсь создать кортеж из Vector
с помощью функции, которая создает настраиваемый тип данных (или кортеж) значений из индекса. Вот подход, который позволяет достичь желаемого результата:
import Prelude hiding (map, unzip)
import Data.Vector hiding (map)
import Data.Array.Repa
import Data.Functor.Identity
data Foo = Foo {fooX :: Int, fooY :: Int}
unfoo :: Foo -> (Int, Int)
unfoo (Foo x y) = (x, y)
make :: Int -> (Int -> Foo) -> (Vector Int, Vector Int)
make n f = unzip $ generate n getElt where
getElt i = unfoo $ f i
За исключением того, что я хотел бы сделать это за одну итерацию для каждого вектора, почти как показано ниже, но избегая многократного вычисления функции f
:
make' :: Int -> (Int -> Foo) -> (Vector Int, Vector Int)
make' n f = (generate n getElt1, generate n getElt2) where
getElt1 i = fooX $ f i
getElt2 i = fooY $ f i
Просто в качестве примечания я понимаю, что библиотека Vector
поддерживает слияние, и первый пример уже довольно эффективен. Мне нужно решение концепции generate
, другие библиотеки имеют очень похожие конструкторы (например, у Repa есть fromFunction
), и я использую здесь Vector
просто для демонстрации проблемы.
Возможно, какое-то запоминание вызова функции f
сработало бы, но я ничего не могу придумать.
Изменить:
Еще одна демонстрация проблемы с использованием Repa:
makeR :: Int -> (Int -> Foo) -> (Array U DIM1 Int, Array U DIM1 Int)
makeR n f = runIdentity $ do
let arr = fromFunction (Z :. n) (\ (Z :. i) -> unfoo $ f i)
arr1 <- computeP $ map fst arr
arr2 <- computeP $ map snd arr
return (arr1, arr2)
Так же, как и с векторами, слияние экономит день на производительности, но по-прежнему требуется промежуточный массив arr
кортежей, которого я пытаюсь избежать.
Изменить 2: (3 года спустя)
В приведенном выше примере Repa он не будет создавать промежуточный массив, так как fromFunction
создает задержанный массив. Вместо этого будет еще хуже, он будет оценивать f
дважды для каждого индекса, один раз для первого массива, второй раз для второго массива. Задержанный массив необходимо вычислять, чтобы избежать такого дублирования работы.
Foo
, которые вы можете сделатьgenerateM
, и нестиIntMap Foo
в монадеState
, то используйтеIntMap
для генерации второго вектора. - person zakyggaps   schedule 24.01.2016Vector
, но, к сожалению, я не могу использовать монаду в этой конкретной ситуации. - person lehins   schedule 24.01.2016