Reputation: 2742
In an attempt to get familiar with the great ideas such as Foldable
, Functor
, etc. I'm writing a data structure for 2*2 matrix. It isn't for real use, so I thought this naive implementation is a good start:
data Matrix2d a = M2 a a a a
I want this to be a Num
instance
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)
-- ....
This does not seem right. I don't want to type +
five times for this obvious definition. Certainly there's room for more abstraction. I'd prefer something like
(+) = fzipWith (+) -- f does not mean anything here
This is actually easy to implement:
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)
however, I couldn't find anything ready-to-use in hoogle. I find it odd because this kind of abstraction seems quite natural. There's Foldable
, there's Functor
--- why not Zippable
?
Questions:
Upvotes: 6
Views: 540
Reputation: 14485
See the adjunctions package, and in particular Data.Functor.Rep.liftR2
.
Your Matrix2
is a representable functor.
Upvotes: 3
Reputation: 62818
You can't do much with just Functor
, but with Applicative
you can do
fzipWith f za zb = f <$> za <*> zb
The default instance for Applicative []
won't do quite what you want; it will take every a
with every b
. But I believe there's a ZipList
newtype somewhere that gives you an instance that zips the way you're expecting. (No, I don't know exactly where it lives.)
Note that this generalises to any number of arguments:
f <$> za <*> zb <*> zc <*> zd
so you don't need the zipWith
, zipWith3
, zipWith4
, etc functions.
Upvotes: 8