Читая комментарии, я немного волнуюсь, что размер здесь под ковром.Есть ли разумное поведение при несовпадении размеров?
Между тем, может быть что-то, что вы можете сделать разумно по следующим направлениям.Даже если ваши массивы нелегко сделать полиморфными, вы можете сделать экземпляр Applicative
подобным этому.
data ArrayLike x = MkAL {sizeOf :: Int, eltOf :: Int -> x}
instance Applicative ArrayLike where
pure x = MkAL maxBound (pure x)
MkAL i f <*> MkAL j g = MkAL (min i j) (f <*> g)
(Энтузиасты заметят, что я взял продукт аппликатива (Int ->)
сэто вызвано (maxBound
, min
) моноидом.)
Не могли бы вы сделать чистое соответствие
imAL :: Image -> ArrayLike Float
alIm :: ArrayLike Float -> Image
с помощью проекции и табулирования?Если это так, вы можете написать такой код:
alIm $ (f <$> imAL a1 <*> ... <*> imAL an)
Более того, если вы хотите обернуть этот шаблон как перегруженный оператор,
imapp :: (Float -> ... -> Float) -> (Image -> ... -> Image)
это стандартное упражнение в классе типовпрограммирование!(Спросите, нужна ли вам дополнительная подсказка.)
Тем не менее, ключевой момент заключается в том, что стратегия оборачивания означает, что вам не нужно манипулировать вашими структурами массива, чтобы поставить функциональную надстройку на верх.