1

Today I am going to write a binary STL file parser and start with the following code:

import Data.Binary.Get
import Data.Word
import Control.Monad
import Data.Bits
import Data.Binary.IEEE754

data Vector3 = Vector3 { x :: Float, y :: Float, z :: Float }

data Triangle = Triangle { normal :: Vector3, 
                           vertex1 :: Vector3, 
                           vertex2 :: Vector3, 
                           vertex3 :: Vector3,
                           attr :: Word16}

getVector3 :: Get Vector3
getVector3 = do
     w1 <- getFloat32le
     w2 <- getFloat32le
     w3 <- getFloat32le
     return $ Vector3 w1 w2 w3    

getTriangle :: Get Triangle
getTriangle = do
     n <- getVector3
     v1 <- getVector3
     v2 <- getVector3
     v3 <- getVector3
     a <- getWord16le
     return $ Triangle n v1 v2 v3 a

stlBinary :: Get ([Triangle])
stlBinary = do
     _ <- getBytes 80 --Ignore the 80 byte header
     cnt <- getWord32be --Read the number of triangles
     replicateM (fromIntegral cnt) getTriangle

The GHC compiler complains

Couldn't match type `binary-0.5.1.1:Data.Binary.Get.Get' with `Get'
Expected type: Get Float
  Actual type: binary-0.5.1.1:Data.Binary.Get.Get Float
In a stmt of a 'do' block: w3 <- getFloat32le
In the expression:
  do { w1 <- getFloat32le;
       w2 <- getFloat32le;
       w3 <- getFloat32le;
       return $ Vector3 w1 w2 w3 }
In an equation for `getVector3':
    getVector3
      = do { w1 <- getFloat32le;
             w2 <- getFloat32le;
             w3 <- getFloat32le;
             .... }

It looks like the Gets from Data.Binary and Data.Binary.IEEE754 conflicts. So how to solve this?

Update

I actually have a workaround -- embedded the implementation of getFloat32le into my code (it is just 6 lines)

getFloat32le :: Get Float
getFloat32le = fmap toFloat getWord32le

toFloat :: (Storable word, Storable float) => word -> float
toFloat word = unsafePerformIO $ alloca $ \buf -> do
    poke (castPtr buf) word
    peek buf

This works, but I still want to know how to due with the name conflicts, since duplicating code is not fun.

UPDATE

$ghc-pkg list binary
/var/lib/ghc/package.conf.d
   binary-0.5.1.1
/home/joe/.ghc/x86_64-linux-7.6.3/package.conf.d
   binary-0.7.2.0
   binary-0.7.2.1
$ ghc-pkg unregister binary-0.5.1.1
ghc-pkg: unregistering binary-0.5.1.1 would break the following packages: 
bin-package-db-0.0.0.0 ghc-7.6.3 buildwrapper-0.8.6 scion-browser-0.3.1 
hoogle-4.2.32 shake-0.12 buildwrapper-0.8.2 dynamic-cabal-0.3.1 
(use --force to override)
$ ghc-pkg unregister binary-0.7.2.0
ghc-pkg: unregistering binary-0.7.2.0 would break the following packages: 
snap-0.13.2.5 pwstore-fast-2.4.1 SHA-1.6.4 Graphalyze-0.14.1.0 
pandoc-1.12.4.2 zip-archive-0.2.3.1 (use --force to override)
$ ghc-pkg unregister binary-0.7.2.1
ghc-pkg: unregistering binary-0.7.2.1 would break the following packages: 
data-binary-ieee754-0.4.4 (use --force to override)

I didn't dare to unregister binary-0.7.2.0 and binary-0.5.1.1, so I unregistereed data-binary-ieee754 and binary-0.7.2.1, reinstalled data-binary-ieee754, and then rebuild, it seems to solved the problem!

Questions:

I still have 2 different binarys, but why it is not a problem this time?

Earth Engine
  • 10,048
  • 5
  • 48
  • 78
  • Did you try the ```-hide-package data-binary-ieee754``` flag on GHC? That should solve this if you're not using anything from Data.Binary.IEEE754. – iamnat Jun 21 '14 at 07:42
  • @tanmaig Unfortunately, I am using `Data.Binary.IEEE754` through `getFloat32le`. – Earth Engine Jun 21 '14 at 07:46
  • Do `ghc-pkg list binary` and then `ghc-pkg unregister binary-` on whichever version is *not* the one that came with GHC (I'm pretty certain that GHC comes with `binary`). It will tell you about all the things this change will break. You will have to unregister and reinstall those things as well. Then, finally, `cabal install data-binary-ieee754 --constraint="binary==*"`. – user2407038 Jun 21 '14 at 08:21

1 Answers1

1

You have encountered cabal hell. If you do the following command:

$ ghc-pkg list binary

You'll see that there are multiple versions of binary installed. The problem is now that Data.Binary.IEEE754 is compiled against a different version of binary than the version you're using to compile your program. And types from different versions of a library never match (the Get type from binary 0.5.1.1 doesn't match the Get type from say binary 0.6).

To fix this, you either have to recompile data-binary-ieee754 against the version used to compile your program, or use another version for compiling (using an explicit -package binary==0.5.1.1 flag when compiling).

If you use cabal >= 1.18 to build, you can also use sandboxes, which should protect you of such problems (not fully, but for most of the time):

$ cabal sandbox init         # Create a new sandbox
$ cabal install --only-dep   # Install only dependencies
$ cabal build                # This will now only use the packages in the sandbox and the system packages

See also http://www.haskell.org/haskellwiki/Cabal/Survival


So, why did it work when you re-installed data-binary-ieee754? I guess what happened is the following:

At beginning, only binary-0.5.1.1 is installed, because it comes with GHC. Now:

  1. You install data-binary-ieee754, which is built against binary-0.5.1.1 (because that is the only version available).
  2. Now, you install some other packages, which require a newer version of binary. => You now have binary-0.5.1.1 and binary-0.7.2.
  3. When you compile a program now, GHC chooses binary-0.7.2, because GHC by default always chooses to use the latest version of any package.
  4. When you recompile data-binary-ieee754, it is now compiled against binary-0.7.2, because that is now the latest version available => everything is compiled against binary-0.7.2 and the types match again.
bennofs
  • 11,873
  • 1
  • 38
  • 62
  • Thanks for this answer! Although I fixed the problem but I still have some questions. Also I think if you could include some source like http://www.haskell.org/haskellwiki/Cabal/Survival it would be good to other users. I found this web site by searching for "cabal hell" as you mentioned. – Earth Engine Jun 21 '14 at 10:36