在 Haskell 中独一无二 id/counter

Unique id/counter in Haskell

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

这是我需要唯一 ID 的示例之一

generateExpression :: AST.Expr -> String
generateExpression (AST.BinOpExpr AST.Or e1 e2) =
            (generateExpression e1) ++
            "    cmpl    [=12=], %eax\n" ++
            "    je      _or_clause2\n" ++
            "    movl    , %eax\n" ++
            "    jmp     _or_end\n" ++
            "_or_clause2:\n" ++           -- need to use a unique id here instead of clause 2
            (generateExpression e2) ++
            "    cmpl    [=12=], %eax\n" ++
            "    movl    [=12=], %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

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

所以return类型里面要有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    [=10=], %eax\n" ++
        "    je      _or_clause" ++ show n ++ "\n" ++
        "    movl    , %eax\n" ++
        "    jmp     _or_end" ++ show n ++ "\n" ++
        "_or_clause" ++ show n ++ ":\n" ++ show n ++
        e2ASM ++
        "    cmpl    [=10=], %eax\n" ++
        "    movl    [=10=], %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。我没有检查你的汇编逻辑是否正确