【问题标题】:Expression for defining letrec implementing little language in Haskell在 Haskell 中定义 letrec 实现小语言的表达式
【发布时间】:2021-03-23 05:41:36
【问题描述】:

我正在为一种小表达式语言编写评估器,但我被困在 LetRec 构造上。

这是语言:

data Expr = Var Nm  | Lam (Nm,Ty) Expr | App Expr Expr
      | Val Int | Add Expr Expr | If Expr Expr Expr
      | Let Nm Expr Expr
      | LetRec [((Nm,Ty),Expr)] Expr

这是目前为止的评估者:

type Env = [ (Nm, Value) ]
data Value = Clos Env Expr
           | Vint Int
       deriving Show

eval :: Env -> Expr -> Value
eval _   (Val n) = Vint n 
eval env (Add e1 e2) = Vint (n1 + n2)  
   where
     Vint n1 = eval env e1  
     Vint n2 = eval env e2
eval env (If e e1 e0) = if n==0 then eval env e0 else eval env e1
                          where 
                            Vint n = eval env e
eval env (Var x) = case lookup x env of
                      Nothing -> error (x)
                      Just v  -> v
eval env (Lam x e) = Clos env (Lam x e)
eval env (App e1 e2) = case v1 of
                        Clos env1 (Lam (x,t) e) -> eval ((x,v2):env1) e
                          where
                            v1 = eval env e1
                            v2 = eval env e2
eval env (Let x e1 e2) = eval env' e2
                        where 
                            env' = (x,v) : env
                            v = eval env e1
eval env (LetRec [((x,t),e)] e1) = eval env' e1
               where
                 env' = env ++ map (\(v,e) -> (v, eval env' e)) [(x,e)]

这是我要评估的测试函数:

t1 = LetRec
    [ (("not",  INT:->INT), Lam ("i",INT) $ If (Var "i")
                                            (Val 0)
                                            (Val 1))
    , (("even", INT:->INT), Lam ("i",INT) $ If (Var "i")
                                            (App (Var "not")
                                                 (App (Var "odd") 
                                                      (Var "i" `Add` Val (-1))))
                                            (Val 1))
    , (("odd",  INT:->INT), Lam ("i",INT) $ If (Var "i")
                                            (App (Var "not") 
                                                 (App (Var "even") 
                                                      (Var "i" `Add` Val (-1))))
                                            (Val 0))
    ]
    (App (Var "odd") (Val 7))

【问题讨论】:

  • 您的具体问题是什么?
  • 我想在上面t1的测试中成功。但是,我解决了 LetRec 中的错误。

标签: haskell evaluation language-implementation mutual-recursion letrec


【解决方案1】:

请注意,您的测试程序是错误的。您不想申请“不”。一个数字n 是即使n-1 IS 奇数,而不是如果它ISN'T 奇数。所以,应该是:

t1 = LetRec
    [ (("even", INT:->INT), Lam ("i",INT) $ If (Var "i")
                                            (App (Var "odd") 
                                                 (Var "i" `Add` Val (-1)))
                                            (Val 1))
    , (("odd",  INT:->INT), Lam ("i",INT) $ If (Var "i")
                                            (App (Var "even") 
                                                 (Var "i" `Add` Val (-1)))
                                            (Val 0))
    ]
  (App (Var "odd") (Val 7))

您的LetRec 案例几乎是正确的。出于某种原因,您刚刚将其编写为仅处理单例列表。此外,您希望将letrec 绑定放在环境绑定列表的开头,而不是结尾,否则letrec 之外的绑定将优先。试试:

eval env (LetRec bnds body) = v
  where v = eval env' body
        env' = [(n, eval env' e) | ((n,_),e) <- bnds] ++ env

这是完整的程序。运行时,应该打印Vint 1:

type Nm = String
data Ty = INT | Ty :-> Ty
  deriving (Show)

data Expr = Var Nm  | Lam (Nm,Ty) Expr | App Expr Expr
          | Val Int | Add Expr Expr | If Expr Expr Expr
          | Let Nm Expr Expr
          | LetRec [((Nm,Ty),Expr)] Expr
          deriving (Show)

type Env = [ (Nm, Value) ]
data Value = Clos Env Expr
           | Vint Int
       deriving (Show)

eval :: Env -> Expr -> Value
eval _   (Val n) = Vint n
eval env (Add e1 e2) = Vint (n1 + n2)
  where
    Vint n1 = eval env e1
    Vint n2 = eval env e2
eval env (If e e1 e0) = if n==0 then eval env e0 else eval env e1
  where
    Vint n = eval env e
eval env (Var x) = case lookup x env of
  Nothing -> error (x ++ " not defined")
  Just v  -> v
eval env e@(Lam _ _) = Clos env e
eval env (App e1 e2) = case v1 of
  Clos env1 (Lam (x,t) e) -> eval ((x,v2):env1) e
  where
    v1 = eval env e1
    v2 = eval env e2
eval env (Let x e1 e2) = eval env' e2
  where
    env' = (x,v) : env
    v = eval env e1
eval env (LetRec bnds body) = eval env' body
  where env' = [(n, eval env' e) | ((n,_),e) <- bnds] ++ env

t1 :: Expr
t1 = LetRec
    [ (("even", INT:->INT), Lam ("i",INT) $ If (Var "i")
                                            (App (Var "odd")
                                                 (Var "i" `Add` Val (-1)))
                                            (Val 1))
    , (("odd",  INT:->INT), Lam ("i",INT) $ If (Var "i")
                                            (App (Var "even")
                                                 (Var "i" `Add` Val (-1)))
                                            (Val 0))
    ]
  (App (Var "odd") (Val 7))

main :: IO ()
main = print (eval [] t1)

【讨论】:

  • 按你写的方法再试一次,我在“函数评估中不存在的部分”出现错误。
  • 我假设您的意思是“函数评估中的非详尽模式”。如果是这样,您运行的代码必须与上面编写的代码不同,因为所有模式都存在(除非您尝试应用非闭包,但错误消息会有所不同)。尝试使用 -Wall 编译并阅读警告以查看您缺少哪些模式。
  • eval _ exp = error $ show exp 现在必须为您提供帮助。
  • 我试过了。但是,我收到以下错误。 LetRec [(("even",INT :-&gt; INT),Lam ("i",INT) (If (Var "i") (App (Var "odd") (Add (Var "i") (Val (-1)))) (Val 1))),(("odd",INT :-&gt; INT),Lam ("i",INT) (If (Var "i") (App (Var "even") (Add (Var "i") (Val (-1)))) (Val 0)))] (App (Var "odd") (Val 7)) CallStack (from HasCallStack): error, called at &lt;interactive&gt;:34:14 in interactive:Ghci3324
  • 我不使用 JupyterLab,所以我不知道如何为您提供帮助。我添加了用于测试的完整程序的副本。它编译和运行没有错误,并为我打印Vint 1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-10
  • 2013-11-18
  • 1970-01-01
相关资源
最近更新 更多