在 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。我没有检查你的汇编逻辑是否正确
我正在尝试在 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。我没有检查你的汇编逻辑是否正确