【问题标题】:Conditionally binding or ignoring a value in do notation有条件地绑定或忽略 do 表示法中的值
【发布时间】:2018-03-13 09:19:51
【问题描述】:

作为一个学习项目,我目前正在尝试在 Haskell 中为 ELF 文件格式构建解析器。 Elf 二进制文件有一个称为程序头的部分,该头包含一个专用于标志的词。程序头包含两个标志字段:一个用于 64 位标志,一个用于 32 位标志,按非顺序排列。

像这样:

data ProgramHeader =
    ProgramHeader {
        getSegmentType :: SegmentType
      , get64SegmentFlags :: SegmentFlag
      , getOffset :: Offset
      , getVirtualAddress :: Address
      , getPhysicalAddress :: Address
      , getFileSize :: Size
      , getMemorySize :: Size
      , get32SegmentFlags :: SegmentFlag
      , getAlignment :: Either Word32 Word64
    }

解析如下:

parseProgramHeader :: WordSize -> Endianness -> Get Program
parseProgramHeader wordsize en = do
  st <- parseSegmentType
  flags64 <- parseSegmentFlag
  offset <- parseVariant wordsize en
  virtualAddress <- parseVariant wordsize en
  physicalAddress <- parseVariant wordsize en
  fileSize <- parseVariant wordsize en
  memorySize <- parseVariant wordsize en
  flags32 <- parseSegmentFlag
  a <- parseVariableWord wordsize
  return $ ProgramHeader st flags64 offset virtualAddress physicalAddress fileSize memorySize flags32 a

现在我希望能够将这两个 SegmentFlag 字段合并为一个字段:

data ProgramHeader =
    ProgramHeader {
        getSegmentType :: SegmentType
      , getSegmentFlags :: SegmentFlag
      , getOffset :: Offset
      , getVirtualAddress :: Address
      , getPhysicalAddress :: Address
      , getFileSize :: Size
      , getMemorySize :: Size
      , getAlignment :: Either Word32 Word64
    }

但是,我仍然需要解析标志字两次(在每个相应的位置),只保留相关的一个。

我的直觉是,这意味着我只需要为相应的 wordsize 绑定 parseSegmentFlag 值;如果不是这种情况,仍然会调用 parseSegmentFlag,但会丢弃该值。 在伪代码中:

parseProgramHeader :: WordSize -> Endianness -> Get Program
parseProgramHeader wordsize en = do
  st <- parseSegmentType
  if wordsize == Bit64
      then
        do flags <- parseSegmentFlag
      else
        discard $ parseSegmentFlag
  [...]
  if wordsize == Bit32
    then do flags <- parseSegmentFlag
    else do discard $ parseSegmentFlag

现在我完全不知道如何在 Haskell 中优雅地执行该操作。有任何想法吗?指针?

谢谢!

【问题讨论】:

  • 在伪代码中,ws 是什么? wordsize?
  • 确实如此 :-)

标签: parsing haskell monads


【解决方案1】:

另一种选择,只需保留您拥有的代码,然后在最后选择相关的版本,即

...  -- as before
let flags = case ws of
                Bit32 -> flags32
                Bit64 -> flags64
return $ ProgramHeader st flags ...

(我使用case 而不是if,因为如果您碰巧添加了另一个案例,您会在此处收到警告,而不是进入您选择的默认分支)

【讨论】:

  • 我怎么没想到!非常感谢@luqui :-)
猜你喜欢
  • 2012-04-13
  • 2020-01-05
  • 1970-01-01
  • 1970-01-01
  • 2020-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
相关资源
最近更新 更多