Haskell中的唯一ID /计数器

时间:2019-05-25 21:55:13

标签: haskell state-monad

我正在尝试在Haskell中生成一些汇编指令,并且需要生成一些唯一的ID来标记jmp指令的节。我相信我可以使用State monad来做到这一点,但是我对Haskell还是陌生的,对State monad不太满意,在这种情况下需要一些帮助。

以下是我需要唯一ID的示例之一

generateExpression :: AST.Expr -> String
generateExpression (AST.BinOpExpr AST.Or e1 e2) =
            (generateExpression e1) ++
            "    cmpl    $0, %eax\n" ++
            "    je      _or_clause2\n" ++
            "    movl    $1, %eax\n" ++
            "    jmp     _or_end\n" ++
            "_or_clause2:\n" ++           -- need to use a unique id here instead of clause 2
            (generateExpression e2) ++
            "    cmpl    $0, %eax\n" ++
            "    movl    $0, %eax\n" ++
            "    setne   %al\n" ++
            "_or_end:\n"                  -- need to use a unique id here to label the end

编辑:我已经阅读了有关State Monad的一些教程,并且可以实现一个简单的计数器,例如

import Control.Monad.State

counter :: State Int Int
counter = do
    x <- get
    put (x+1)
    return x

runState counter 1 -- outputs (1,2) where the state has been incremented

,它将跟踪计数器作为状态。但是我不确定如何在需要在递归调用中保持状态的函数中使用它。

1 个答案:

答案 0 :(得分:4)

因此返回类型中必须包含State Int,不能为String。关键是您需要使状态通过。在这里,您似乎对此感到满意,所以使用了do表示法。

counter :: State Int Int
counter = do
    n <- get
    put (n + 1)
    pure n

generateASM :: AST.Expr -> State Int String
generateASM (AST.BinOpExpr AST.Or e1 e2) = do
    e1ASM <- generateASM e1
    n <- counter
    e2ASM <- generateASM e2
    pure $
        e1ASM ++
        "    cmpl    $0, %eax\n" ++
        "    je      _or_clause" ++ show n ++ "\n" ++
        "    movl    $1, %eax\n" ++
        "    jmp     _or_end" ++ show n ++ "\n" ++
        "_or_clause" ++ show n ++ ":\n" ++ show n ++
        e2ASM ++
        "    cmpl    $0, %eax\n" ++
        "    movl    $0, %eax\n" ++
        "    setne   %al\n" ++
        "_or_end" ++ show n ++ ":\n"
generateASM (..) = .. -- other branches defined similarly...

generateASMFull :: AST.Expr -> String
generateASMFull e = evalState (generateASM e) 0

P.S。我没有检查您的汇编逻辑是否正确。