1

今天我要写一个二进制STL 文件解析器,从下面的代码开始:

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

GHC 编译器抱怨

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;
             .... }

它看起来像Gets fromData.BinaryData.Binary.IEEE754冲突。那么如何解决这个问题呢?

更新

我实际上有一个解决方法——将实现嵌入getFloat32le到我的代码中(只有 6 行)

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

这可行,但我仍然想知道如何处理名称冲突,因为复制代码并不好玩。

更新

$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)

我不敢注销binary-0.7.2.0and binary-0.5.1.1,所以我注销data-binary-ieee754and binary-0.7.2.1,重新安装data-binary-ieee754,然后rebuild,好像问题解决了!

问题:

我还有2个不同binary的s,但是为什么这次没有问题呢?

4

1 回答 1

1

你遇到了阴谋集团的地狱。如果您执行以下命令:

$ ghc-pkg list binary

您会看到安装了多个版本的二进制文件。现在的问题是,它Data.Binary.IEEE754是针对与您用于编译程序的版本不同的二进制版本编译的。并且来自不同版本库的类型永远不会匹配(Get二进制 0.5.1.1 中的Get类型与二进制 0.6 中的类型不匹配)。

要解决此问题,您必须data-binary-ieee754针对用于编译程序的版本重新编译,或者使用另一个版本进行编译(编译-package binary==0.5.1.1时使用显式标志)。

如果你使用 cabal >= 1.18 来构建,你也可以使用沙箱,它应该可以保护你免受此类问题的影响(不是完全,但在大多数情况下):

$ 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

另见http://www.haskell.org/haskellwiki/Cabal/Survival


那么,为什么重新安装时它会起作用data-binary-ieee754?我猜发生的事情如下:

一开始只binary-0.5.1.1安装了,因为它自带GHC。现在:

  1. 您安装data-binary-ieee754,它是针对binary-0.5.1.1(因为这是唯一可用的版本)构建的。
  2. 现在,您安装了一些其他软件包,它们需要更新版本的binary. => 你现在有binary-0.5.1.1binary-0.7.2
  3. 现在编译程序时,GHC 会选择binary-0.7.2,因为默认情况下 GHC 总是选择使用任何包的最新版本。
  4. 当您重新编译时data-binary-ieee754,它现在是针对 编译的binary-0.7.2,因为现在是可用的最新版本 => 一切都针对它进行编译binary-0.7.2并且类型再次匹配。
于 2014-06-21T08:14:36.020 回答