【发布时间】:2017-11-18 23:20:12
【问题描述】:
我正在用 Haskell 编写一个非常简单的两遍汇编程序,我遇到了一个我还没有经验来解决的场景。我认为解决方案很可能涉及 monad 转换器,我不太了解。
汇编器将汇编代码解析为Statements 的列表,这些列表可以是指令也可以是标签。一些Statements 可能会引用标签。汇编器需要将Statements 转换为Instructions,这包括消除标签并用适当的值替换标签引用。
我已经编写了汇编程序的第一遍,它产生了一个[(String, Int)],表示从标签到地址的映射。我还编写了以下函数,用于将Statement 转换为Instruction:
stmtToInstruction :: Int -> [(String, Int)] -> Statement -> Either String [I.Instruction]
stmtToInstruction addr labels stmt = case stmt of
ADD d s1 s2 -> Right [I.ADD d s1 s2]
BEQL s1 s2 l -> case do label <- find (\e -> fst e == l) labels
let labelAddr = snd label
let relativeAddr = I.ImmS $ fromIntegral (labelAddr - addr)
return (I.BEQ s1 s2 relativeAddr) of
Just i -> Right [i]
Nothing -> Left $ "Label " ++ l ++ " not defined"
LABEL _ -> Right []
为简洁起见,我省略了几个案例,但您可以在此处查看所有可能的结果:
-
ADD总是成功并产生指令 -
BEQL可以成功也可以失败,这取决于是否找到标签 -
LABEL总是成功,即使它没有产生实际的指令
这按预期工作。我现在遇到的问题是写这个函数:
replaceLabels :: [Statement] -> Either String [I.Instruction]
replaceLabels 获取一个语句列表,并在每个语句上运行stmtToInstruction。 stmtToInstruction 的 addr 参数必须是到目前为止累积的 [Instruction] 的长度。如果标签引用之一无效,则输出可能是 Left String,如果没有错误,则输出可能是 Right [I.Instruction]。
mapM :: Monad m => (a -> m b) -> [a] -> m [b] 为我们提供了一些方法,但无法将当前地址注入(a -> m b) 函数。我该如何完成这项工作?
【问题讨论】:
-
你可以使用懒惰一次性完成 - 使用地图打结。
-
@Alec 你能指点我关于这种方法的任何资源吗?
-
foldM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b看起来离我更近了:hackage.haskell.org/package/base-4.10.0.0/docs/… -
bobkonf.de/2016/breitner-monaden.html 是一个资源,虽然是德语。 wall.org/~lewis/2013/10/15/asm-monad.html 是英文的。
标签: haskell monads monad-transformers