更新时间:2023-02-27 08:48:02
如果我理解正确你的问题,你可以向函数添加一个额外的参数 free-index 像这样:
If I understand correctly your problem, you can add to the function an extra parameter free-index like this:
transform :: Stmt -> FStmt
transform = snd . transform' 0
transform' :: Int -> Stmt -> (Int, FStmt)
transform' freeIdx (Seq stmt) = (freeIdx', FSeq stmt')
where
(freeIdx', stmt') = mapAccumL transform' freeIdx stmt
transform' freeIdx (Assign var val) = (freeIdx, FAssign var val)
transform' freeIdx (While cond stmt) =
(freeIdx', FWhile label1 (Jumpf cond label2) stmt' (Jump label1) label2)
where
label1 = "label" ++ show freeIdx
label2 = "label" ++ show (freeIdx + 1)
(freeIdx', stmt') = transform' (freeIdx + 2) stmt
transform' freeIdx (If cond stmt1 stmt2) =
(freeIdx'', FIf (Jumpf cond label) stmt1' label stmt2')
where
label = "label" ++ show freeIdx
(freeIdx', stmt1') = transform' (freeIdx + 1) stmt1
(freeIdx'', stmt2') = transform' freeIdx' stmt2
但是如果你知道 State monad,你可以这样设计:
But if you known State monad, you can design like this:
transform :: Stmt -> FStmt
transform = flip evalState 0 . transform'
transform' :: Stmt -> State Int FStmt
transform' (Seq stmt) = FSeq <$> mapM transform stmt
transform' (Assign var val) = return $ FAssign var val
transform' (While cond stmt) = do
label1 <- freeLabel
label2 <- freeLabel
stmt' <- transform' stmt
return $ FWhile label1 (Jumpf cond label2) stmt' (Jump label1) label2
transform' (If cond stmt1 stmt2) = do
label <- freeLabel
stmt1' <- transform' stmt1
stmt2' <- transform' stmt2
return $ FIf (Jumpf cond label) stmt1' label stmt2'
freeLabel :: State Int String
freeLabel = do
i <- get
put $ i + 1
return $ "label" ++ show i