在 Haskell 中定义 letrec 实现小语言的表达式
Expression for defining letrec implementing little language in Haskell
我正在为一种小型表达式语言编写一个求值器,但我被困在 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))
注意你的测试程序是错误的。你不想申请“不”。如果 n-1
IS 奇数,n
是偶数,如果 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)
我正在为一种小型表达式语言编写一个求值器,但我被困在 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))
注意你的测试程序是错误的。你不想申请“不”。如果 n-1
IS 奇数,n
是偶数,如果 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)