Question

Following my previous question about Data.Vector.Generic.Vector instances I began to wonder, why

zipWith :: (Vector v a, Vector v b, Vector v c)
        => (a -> b -> c) -> v a -> v b -> v c
zipWith f xs ys = unstream (Stream.zipWith f (stream xs) (stream ys))

and not

zipWith :: (GV.Vector v1 a, GV.Vector v2 b, GV.Vector v3 c) 
        => (a -> b -> c) -> v1 a -> v2 b -> v3 c
zipWith f xs ys = unstream (Stream.zipWith f (stream xs) (stream ys))

?

Second one compiles just fine. Are there any particular reasons to restrict all such function to one instance? Because for me

v1 = Data.Vector.fromList [1,2,3,4,5]
v2 = Data.Vector.Unboxed.fromList [6,7,8,9] :: Data.Vector.Unboxed.Vector Int
v3 = foo (*) v1 v2 :: Data.Vector.Unboxed.Vector Int
v4 = foo (*) v1 v2 :: Data.Vector.Vector Int 

looks WAY more 'generic'.

Était-ce utile?

La solution

The main advantage, IMO, of a single v in the signature is that this can then always be infered from any one of the arguments. With the more polymorphic approach, you'd end up having to write awkward explicit type signatures for intermediate expressions (probably necessiating -XScopedTypeVariables when typically the choice would be just "use the same Vector flavour as for the other argument" (which is probably the best choice performance-wise, and just the obvious one). Often it simply won't matter much, then it's nice not to have to worry about type signatures at all. OTOH, if you need to combine different Vector instances, the precise type being fixed elsewhere, it's a trivial matter of throwing in GV.convert before one of the arguments to get to the more polymorphic version. Much easier that making it less polymorphic, somewhat surprisingly.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top