繁体   English   中英

Haskell递归

[英]Haskell Recursion

我一直在为给定表达式中的变量添加计数器,并具有以下测试用例:

prop_add1 = add (And (Var "a") (And (Var "b") (Var "a"))) ==
And (Var "a1") (And (Var "b2") (Var "a1"))

我一直在使用模式匹配和递归来尝试找到解决方案。 尽管有些卡住,但我尝试将原始变量添加到列表中,然后使用列表确定要输出的变量名称,但我不知道如何正确实现它,我的输出仅添加了1到所有变量的末尾。

我想知道是否有更好/更轻松的解决方案?

到目前为止,我的尝试:

add :: Expr -> Expr
add T = T
add (Var x) = Var (x ++ show (check2(check x)))
add (And e1 e2) = And (add e1) (add e2)
add (Not e1) = Not (add e1)

check :: Variable -> [Variable]
check p = [p]

check2 :: [Variable] -> Int
check2 p = length (union p p)

您需要保留一个将变量名映射为数字的环境。 就像是

add :: Expr -> Expr
add expr = fst $ addWithEnv emptyEnv expr
  where
    emptyEnv = []
    addWithEnv env (And e1 e2)
        = case addWithEnv env e1 of
            (e1', env') ->
              case addWithEnv env' e2 of
                (e2', env'') -> (And e1' e2', env'')
    addWithEnv env (Var name)
        = case lookup name env of
            Just k -> -- stopping here,it's homework

希望我已经留给您足够的信息。

更新:

在尝试时,您不会跟踪已经看到的变量,因此每个变量似乎都是第一个,并且每次附加“ 1”。 编号项目是有状态的计算,您必须记录迄今为止已看到的变量,才能将以前看到的变量分配给旧编号,并知道要分配下一个尚未看到的变量的编号。 因此,您必须随身携带该记录。 如果您已经知道Monad类及其使用方法,则可以使用State monad隐式地携带它,否则必须显式携带它。 然后add成为包装器,该包装器以初始为空的状态调用工作器(在编号/重新命名开始之前,尚未看到任何变量)。 然后,工作程序查看给定表达式的子表达式(如果有),并重命名变量并在遇到新变量时更新状态。

所以在上面的草图中,我们有

addWithEnv :: [(String,Int)] -> Expr -> (Expr, [(String,Int)])

由于我们无法更改状态,因此我们必须返回新状态以及重命名的表达式。 现在,您必须定义每种表达式类型的结果,

addWithEnv env T = ??
addWithEnv env (Var name) = ??
addWithEnv env (Add e1 e2) = ??
addWithEnv env (Not e) = ??

T情况当然不会重命名,也不会更新环境。 Var以前已经见过,在这种情况下,环境保持不变,或者没有,在这种情况下将其添加到环境中。 Not e对环境的影响与e ,而And e1 e2 e2对环境的影响首先是e1然后是e2

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM