【问题标题】:Trying to read a byte (Word8) by offset in Haskell and getting various error试图通过 Haskell 中的偏移量读取一个字节(Word8)并得到各种错误
【发布时间】:2016-10-05 05:20:00
【问题描述】:

我在下面有一个名为 test2.hs 的文件,我试图通过二进制文件中的偏移量读取一个字节(Word8)并将其用作 Int。下面的例子是试图读取二进制文件中的第二个字节。

import qualified Data.ByteString.Lazy as BS
import Data.Word
import Data.Bits
import Data.Binary.Get

getuint8 = do
    uint8 <- getWord8
    return uint8

readuint8 :: BS.ByteString -> Int -> Int
readuint8 contents startpos = do
    return $ runGet getuint8 (drop startpos contents)

main :: IO ()
main = do
    let myfile = "DATA.BIN"
    contents <- BS.readFile myfile
    let stuff = readuint8 contents 1
    print stuff

不太清楚为什么会出现以下错误:

test2.hs:12:9: error:
    • Couldn't match expected type ‘Int’ with actual type ‘m0 Word8’
    • In a stmt of a 'do' block:
        return $ runGet getuint8 (drop startpos contents)
      In the expression:
        do { return $ runGet getuint8 (drop startpos contents) }
      In an equation for ‘readuint8’:
          readuint8 contents startpos
            = do { return $ runGet getuint8 (drop startpos contents) }

test2.hs:12:35: error:
    • Couldn't match expected type ‘BS.ByteString’
                  with actual type ‘[a0]’
    • In the second argument of ‘runGet’, namely
        ‘(drop startpos contents)’
      In the second argument of ‘($)’, namely
        ‘runGet getuint8 (drop startpos contents)’
      In a stmt of a 'do' block:
        return $ runGet getuint8 (drop startpos contents)

test2.hs:12:49: error:
    • Couldn't match expected type ‘[a0]’
                  with actual type ‘BS.ByteString’
    • In the second argument of ‘drop’, namely ‘contents’
      In the second argument of ‘runGet’, namely
        ‘(drop startpos contents)’
      In the second argument of ‘($)’, namely
        ‘runGet getuint8 (drop startpos contents)’

【问题讨论】:

    标签: haskell byte


    【解决方案1】:

    类型错误

    您的大多数问题都是类型错误。这些是编写 Haskell 程序时最常见的编译器错误消息类型。让我们看一个示例函数:

    readuint8 :: BS.ByteString -> Int -> Int
    

    此函数将接受ByteStringInt,然后返回Int

    readuint8 contents startpos 
    

    所以内容是ByteStringstartposInt

           = do
        return $ 
    

    由于某种原因,您正在使用 do 表示法,但类型 (Int) 不是 monad(它会显示为 IO Int[Int] 或更一般的 m Int)。 问题 1 您不应在此处使用 doreturn,而应仅使用以下表达式:

    runGet getuint8 (drop startpos contents)
    

    前奏中定义的drop 函数作用于列表,而不是字节串。 问题 2 你可能想要BS.drop。由于字节串删除需要Int64 参数,这与Int 不同,您应该通过fromIntegral 进行转换。请注意,删除字节意味着 startpos 的索引为零。

    现在类型是...无论getuint8 的类型是什么。注意这个函数定义是多余的——它等于getuint8 = getWord8。您没有显式键入getuint8,但类型被推断为Get Word8问题 3 混合使用 Word8Int 类型是一个问题 - readuint8 需要 Int,这与 Word8 不同。您可以使用fromIntegral 在整数类型之间进行转换,因此请考虑:

    fromIntegral (runGet getuint8 (BS.drop (fromIntegral startpos) contents))
    

    另类

    考虑解压字节串并对其进行索引:

    main :: IO ()
    main = do
        let myfile = "DATA.BIN"
        contents <- BS.readFile myfile
        let stuff = drop 1 (BS.unpack contents)
        case stuff of
            (firstByte:restOfTheBytes)    -> print firstByte
             [] {- empty list of bytes -} -> putStrLn "The file was not that long."
    

    考虑对原始结构进行一些轻微压实:

    main :: IO ()
    main = print . runGet getWord8 . BS.drop 1 =<< BS.readFile "DATA.BIN"
    

    从右到左读取文件,丢弃一个字节,获取第一个Word8值,打印该值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-03
      • 1970-01-01
      • 2018-05-26
      相关资源
      最近更新 更多