Data.Vector.Binary overlaps Binary [a] instance
Asked Answered
Y

1

7

In my application I need to serialize a vector containing an arbitrary datatype, in this case is a list of Doubles. For serializing the vector I'm importing Data.Vector.Binary.

When loading the module in GHCi the following error arises:

Overlapping instances for Binary [Double]
  arising from a use of `decode' at Statistics.hs:57:33-42
Matching instances:
  instance (Data.Vector.Generic.Base.Vector v a, Binary a) =>
           Binary (v a)
    -- Defined in Data.Vector.Binary
  instance (Binary a) => Binary [a] -- Defined in Data.Binary

Is the list an instance of Vector? I looked through the documentation but could not find such instance.

What can I do to be able to serialize this structure?

Edit:

I'm using the following package versions:

  • vector-0.6.0.2
  • vector-binary-instances-0.1.2
  • binary-0.5.0.2

Also here is a snippet that shows the issue, this time with a list of chars:

import Data.Binary
import Data.Vector.Binary
import qualified Data.ByteString.Lazy as L

main = L.writeFile "/tmp/aaa" $ encode "hello"
Yeast answered 25/7, 2010 at 12:31 Comment(3)
Could you please post which versions of Binary and Vector you're using?Valrievalry
I agree that GHCi seems to be assuming that lists are vectors. I've looked through the source code for vector-binary-instances and not found it.Melee
It's not obvious. Edward Kmett explained this issue not long ago in #3213990Valrievalry
V
7

Ok, I think I see the problem here. The vector-binary-instances package defines:

instance (Data.Vector.Generic.Base.Vector v a, Binary a) => Binary (v a)

which is very bad. This definition means "for any type 'v a', this is a valid Binary instance". That means this instance is available for any type that matches v a. That includes (but is not limited to) all lists, all functors, and all monads. As a demonstration, ghci reports the following:

Prelude Data.Binary Data.Vector.Binary Data.ByteString.Lazy> :t getChar
getChar :: IO Char
Prelude Data.Binary Data.Vector.Binary Data.ByteString.Lazy> encode getChar
<interactive>:1:0:
    No instance for (Data.Vector.Generic.Base.Vector IO Char)
      arising from a use of `encode' at <interactive>:1:0-13
    Possible fix:
      add an instance declaration for
      (Data.Vector.Generic.Base.Vector IO Char)
    In the expression: encode getChar
    In the definition of `it': it = encode getChar

Here the interpreter is attempting to use this instance for getChar :: IO Char, which is obviously wrong.

Short answer: don't use vector-binary-instances for now. This instance is broken, and given how instances propagate through Haskell code it will cause problems. Until this is fixed, you should write your own binary instances for vectors. You should be able to copy the code from vector-binary-instances and restrict it to a monomorphic vector type

instance (Binary a) => Binary (Vector a) where

I believe this will work with any Vector which is an instance of Data.Vector.Generic.Vector.

You also may want to contact the vector-binary-instances maintainer about this.

Valrievalry answered 25/7, 2010 at 17:41 Comment(3)
Thank you very much for the explanation, also the link to Edward Kmett's answer helped in understanding why it happens. Citing him: 'In many ways, the syntax for 'instance' and 'class' definitions is backwards.'. I'll follow your suggestions, for which I'm grateful.Yeast
The package has been updated. I just enumerate the boxed and unboxed vector cases separately now (note you can't just use 'Vector a', as that's only the boxed ones).Coterie
@DonStewart thanks for fixing this. It would be nice if instance selection depended on class contexts, but I'm pretty sure that would be a major change with lots of unintended consequences.Valrievalry

© 2022 - 2024 — McMap. All rights reserved.