Здесь есть основной вопрос монады, не связанный с Репой, плюс несколько конкретных вопросов, связанных с Репой.
Я работаю над библиотекой, использующей Repa3. У меня возникли проблемы с получением эффективного параллельного кода. Если я заставлю свои функции возвращать массивы с задержкой, я получаю мучительно медленный код, который очень хорошо масштабируется до 8 ядер. Этот код занимает более 20 ГБ памяти для профилировщика GHC и работает на несколько порядков медленнее, чем базовые нерасположенные векторы Haskell.
В качестве альтернативы, если я заставлю все мои функции возвращать массивы манифеста Unboxed (все еще пытаясь использовать слияние внутри функций, например, когда я делаю "карту" ), я получаю МНОГО быстрый код (все еще медленнее, чем использование нерасположенных векторов Haskell), который вообще не масштабируется и на самом деле имеет тенденцию становиться немного медленнее с большим количеством ядер.
На основе кода примера FFT в Repa-Algorithms кажется правильным подход всегда возвращать манифестные массивы. Есть ли когда-нибудь случай, когда я должен возвращать отложенные массивы?
Код FFT также позволяет использовать функцию "сейчас" . Тем не менее, я получаю ошибку типа, когда я пытаюсь использовать ее в своем коде:
type Arr t r = Array t DIM1 r
data CycRingRepa m r = CRTBasis (Arr U r)
| PowBasis (Arr U r)
fromArray :: forall m r t. (BaseRing m r, Unbox r, Repr t r) => Arr t r -> CycRingRepa m r
fromArray =
let mval = reflectNum (Proxy::Proxy m)
in \x ->
let sh:.n = extent x
in assert (mval == 2*n) PowBasis $ now $ computeUnboxedP $ bitrev x
Код компилируется без "now". С "now" я получаю следующую ошибку:
Не удалось совместить тип
r' with
Array U (Z:. Int) r ' "r" - это жесткая переменная типа, связанная подпись типа для fromArray:: (BaseRing m r, Unbox r, Repr t r) = > Arr t r → CycRingRepa m r на C:\Users\crockeea\Documents\Code\LatticeLib\CycRingRepa.hs: 50: 1 Ожидаемый тип: CycRingRepa m r Фактический тип: CycRingRepa m (массив U DIM1 r)
Я не думаю, что это является моей проблемой. Было бы полезно, если бы кто-то мог объяснить, как работает Монада "сейчас" . По моей наилучшей оценке, монада, похоже, создает "Arr U (Arr U r)". Я ожидаю "Arr U r", который затем будет соответствовать шаблону конструктора данных. Что происходит и как это исправить?
Подписи типов:
computeUnboxedP :: Fill r1 U sh e => Array r1 sh e -> Array U sh e
now :: (Shape sh, Repr r e, Monad m) => Array r sh e -> m (Array r sh e)
Было бы полезно иметь лучшее представление о том, когда целесообразно использовать "сейчас" .
Еще пара вопросов, связанных с Repa: Должен ли я явным образом вызывать computeUnboxedP (как в примере кода FFT), или я должен использовать более общий computeP (потому что часть unbox определяется по моему типу данных)? Должен ли я хранить запаздывающие или манифестные массивы в типе данных CycRingRepa? В конце концов, мне также хотелось бы, чтобы этот код работал с Haskell Integer. Будет ли это требовать от меня написать новый код, который использует что-то другое, чем U-массивы, или я могу написать полиморфный код, который создает U-массивы для типов unbox и другого массива для целых чисел/типов в ящике?
Я понимаю, что здесь много вопросов, и я ценю любые/все ответы!