2015-06-30 2 views
6

В попытке познакомиться с замечательными идеями, такими как Foldable, Functor и т. Д. Я пишу структуру данных для матрицы 2 * 2. Это не для реального использования, так что я думал, что это наивная реализация является хорошим началом:Класс "Zippable" для haskell?

data Matrix2d a = M2 a a a a 

Я хочу, чтобы это было Num экземпляру

instance Num a => Num (Matrix2d a) where 
    (M2 a0 b0 c0 d0) + (M2 a1 b1 c1 d1) = M2 (a0+a1) (b0+b1) (c0+c1) (d0+d1) 
    -- .... 

Это не кажется правильным. Я не хочу набирать + пять раз за это очевидное определение. Конечно, есть место для большей абстракции. Я предпочел бы что-то вроде

(+) = fzipWith (+) -- f does not mean anything here 

Это на самом деле легко реализовать:

class Zippable z where 
    fzipWith :: (a -> b -> c) -> z a -> z b -> z c 

instance Zippable Matrix2 where 
    fzipWith f (M2 x y z w) (M2 a b c d) = M2 (f x a) (f y b) (f z c) (f w d) 

однако, я не мог найти ничего, готовый к использованию в hoogle. Я нахожу это странным, потому что эта абстракция кажется вполне естественной. Там Foldable, есть Functor --- почему бы не Zippable?

Вопросы:

  • Есть ли модуль, который обеспечивает эту функцию?
  • Если нет (я считаю, что это так), какие у меня варианты? Является ли определение моего собственного класса лучшим выбором или есть лучшая альтернатива?
+1

У вас есть хэскелл: http://learnyouahaskell.com/functors-applicative-functors-and-monoids – AJFarmar

+2

Это не супер практический ответ, а [F-алгебры] (https: //lukepalmer.wordpress. com/2013/03/12/construct-on-typeclasses-part-1-f-albums /) обеспечивают очень правильную структуру для получения функций типа '(+)' бесплатно. – luqui

ответ

6

Вы не можете делать только с Functor, но с Applicative вы можете сделать

fzipWith f za zb = f <$> za <*> zb 

экземпляр по умолчанию для Applicative [] не будет делать совсем то, что вы хотите; он принимает каждыеa с каждыеb. Но я считаю, что есть где-то ZipList newtype, который дает вам экземпляр, который застегивается так, как вы ожидаете. (Нет, я не знаю точно, где она живет.)

Обратите внимание, что это обобщается на любое количество аргументов:

f <$> za <*> zb <*> zc <*> zd 

так что вам не нужно zipWith, zipWith3, zipWith4, и т.д.

+0

Не могли бы вы добавить пример реализации? Я написал [это] (https://gist.github.com/anonymous/417585e7f6d54ddfc7fd) с вашим предложением, все в порядке? – Yosh

+0

@Yosh Ваша реализация выглядит хорошо для меня. – MathematicalOrchid

+1

[default] (https://github.com/agda/agda-stdlib/blob/master/src/Data/Vec.agda#L69) Пример «Аппликативный» для векторов кодирует zipping. Перевод в Haskell прост. – user3237465

2

См. Пакет дополнений, и в частности Data.Functor.Rep.liftR2.

Ваш Matrix2 является представимым функтором.

Смежные вопросы