从ByteString中使用“ get”解析Float行为不符合预期

时间:2019-12-08 01:04:13

标签: parsing haskell

在创建一个简单的STL解析器的上下文中,至少在我看来,get的{​​{1}}中出现了一些意外行为。在我看来,它在我认为应该的32位之后不再停止读取Data.Binary

ByteString

尝试使用此代码读取STL文件,我会收到类似的错误

{-# LANGUAGE FlexibleContexts #-}
module STLTransform where

import qualified Data.ByteString.Lazy as BL
import Data.Binary
import Data.Binary.Get
import Data.Binary.Put
import Data.Word
import Numeric.LinearAlgebra
import GHC.Float
import System.Endian

getTriangle = do
  normal   <- getR3
  vertices <- sequence $ take 3 $ trace (show normal) $ repeat getR3
  return (normal, vertices)
  where getR3 = fmap (vector.fmap float2Double)
              $ sequence $ take 3 $ repeat get

getSTL :: Get ([Word8], Word32, [(Vector R, [Vector R])], Word16)
getSTL = do
  header <- sequence $ take 80 $ repeat get
  number <- fmap (toBE32) $ get
  triangles <- sequence $ take (fromIntegral number) $ repeat getTriangle
  attribute <- get
  return (header, number, triangles, attribute)

readSTL fn = BL.readFile fn >>= return.runGet getSTL

经过一些调试后,我将问题隔离到*Main STLTransform> readSTL "test.stl" *** Exception: Data.Binary.Get.runGet at position 1268784: not enough bytes CallStack (from HasCallStack): error, called at libraries/binary/src/Data/Binary/Get.hs:351:5 in binary-0.8.6.0:Data.Binary.Get ,更具体地说,将其解析为getTriangle的值。通过将Float替换为float2Double

(\a -> fromIntegral (a :: Word32))

我得到的代码可以按预期运行(尽管显然数字不正确)。所以问题是,为什么getTriangle = do normal <- getR3 vertices <- sequence $ take 3 $ trace (show normal) $ repeat getR3 return (normal, vertices) where getR3 = fmap (vector.fmap (\a -> fromIntegral (a :: Word32))) $ sequence $ take 3 $ repeat get Float被区别对待? Word32也是32位值吗?

使用的软件包版本为Float

编辑: 该函数的更正版本是

binary-0.8.6.0

与上述问题无关,但已从原始帖子中更正,该属性位于三角形级别,而不是文件级别。

1 个答案:

答案 0 :(得分:1)

The Binary instance of Float解析一对 (Integer, Int)then uses encodeFloat :: Integer -> Int -> Float,这就是为什么它占用超过32位的原因。

这是一个向后兼容的已知问题:https://github.com/kolmodin/binary/issues/69

不要盲目使用get,不止一种编码方式。在这种情况下,还有用于Float的32位格式的其他解析器:https://hackage.haskell.org/package/binary-0.8.7.0/docs/Data-Binary-Get.html#v:getFloatbe