Выражение для определения letrec, реализующего небольшой язык в 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))

Каков ваш конкретный вопрос?

Robert Harvey 11.12.2020 20:39

Я хочу преуспеть в тесте t1 выше. Однако в LetRec есть ошибка, которую я решил.

whoareu 12.12.2020 15:33
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
260
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Обратите внимание, что ваша тестовая программа неверна. Вы не хотите применять «не». Число n четное, если n-1 НЕчетное, а не если оно НЕ НЕЧЕТНОЕ. Итак, должно быть:

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)

Попробуйте еще раз, как вы написали, и я получил ошибку «Несуществующие части в функции eval».

whoareu 12.12.2020 15:32

Я предполагаю, что вы имеете в виду «Неисчерпывающие шаблоны в функции eval». Если это так, вы должны запускать код, отличный от того, что вы написали выше, потому что все шаблоны присутствуют (кроме случаев, когда вы пытаетесь применить незамыкание, но сообщение об ошибке будет другим). Попробуйте скомпилировать с помощью -Wall и прочитайте предупреждения, чтобы увидеть, какие шаблоны вам не хватает.

K. A. Buhr 12.12.2020 15:48
eval _ exp = error $ show exp должен помочь вам на данный момент.
Akihito KIRISAKI 13.12.2020 15:33

Я пытался. Однако я получил следующую ошибку. LetRec [(("even",INT :-> INT),Lam ("i",INT) (If (Var "i") (App (Var "odd") (Add (Var "i") (Val (-1)))) (Val 1))),(("odd",INT :-> 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 <interactive>:34:14 in interactive:Ghci3324

whoareu 13.12.2020 16:17

Я не пользуюсь JupyterLab, поэтому не знаю, как вам с этим помочь. Я добавил копию полной программы, которую использовал для тестирования. Он компилируется и запускается без ошибок и печатает Vint 1 для меня.

K. A. Buhr 13.12.2020 19:26

Большое спасибо за подробное объяснение!! Я погуглил и решил проблему Jupyterlab, используя информацию

whoareu 14.12.2020 09:00

Другие вопросы по теме