whoareu
whoareu

Reputation: 63

Expression for defining recursive function

How do I use recursive function in Haskell?

I'm writing an evaluator for a little expression language, but I'm stuck on the Rec construct.

This is the language:

    data Expr = Var Nm  | Lam (Nm,Ty) Expr | App Expr Expr
          | Val Int | Add Expr Expr | If Expr Expr Expr
          | Rec Expr         

And this the evaluator so far:

    type Env = [ (Nm, Value) ]
    data Value = Clos Env Expr
               | Vint Int
           deriving Show
    ev :: Env -> Expr -> Value
    ev _   (Val n) = Vint n 
    ev env (Add e1 e2) = Vint (n1 + n2)  
       where
         Vint n1 = ev env e1  
         Vint n2 = ev env e2
    ev env (If e e1 e0) = if n==0 then ev env e0 else ev env e1
                              where 
                                Vint n = ev env e
    ev env (Var x) = case lookup x env of
                          Nothing -> error (x)
                          Just v  -> v
    ev env (Lam x e) = Clos env (Lam x e)
    ev env (App e1 e2) = case v1 of
                            Clos env1 (Lam (x,t) e) -> ev ((x,v2):env1) e
                              where
                                v1 = ev env e1
                                v2 = ev env e2

I would like to call the actual recursive function and execute it to get the sum from 1 to 100.

This is my test function I want to evaluate:

    t1 = Rec  (Lam ("f", INT :-> INT) . Lam ("i", INT) $
                If (Var "i")
                    (Var "i" `Add` (App (Var "f") (Var "i" `Add` Val(-1))))
                    (Var "i")
            )
    ev [] (App t1 (Val 100))

asnwer : Vint 5050

I've tried to make expression.

but,I got this error, ":(6,1)-(29,98): Non-exhaustive patterns in function ev"
I think there is a running error because the recursive function is not working properly.
Can you help me solve the problem?

Upvotes: 1

Views: 320

Answers (1)

K. A. Buhr
K. A. Buhr

Reputation: 51159

You might be looking for:

eval env (Rec (Lam (f,t) e)) = v
  where v = eval ((f,v):env) e

It's a little tricky. The idea is to close the body e of the Rec (Lam ...) construction in an environment that binds f to the value v of the returned closure itself. The easiest way to do it is using the recursive construction above, where the returned closure v references its own value in its context, lifting the recursive binding in your expression language to a recursive binding in Haskell.

Alternatively, if you don't want to use a recursive binding in the host language, there are other ways to do it. You can introduce a new value that represents a recursively bound closure:

data Value = ...
       | Loop Nm Value  -- this Value is a Clos
       ...

and then evaluating a Rec produces a Loop in place of the recursive binding:

eval env (Rec (Lam (f,t) e)) = Loop f (eval env e)

and you add a case to your App evaluator to handle the recursion:

eval env (App e1 e2) = case v1 of
  Loop f (Clos env1 (Lam (x,t) e)) -> eval ((x,v2):(f,v1):env1) e
  Clos env1 (Lam (x,t) e) -> eval ((x,v2):env1) e
  where
    v1 = eval env e1
    v2 = eval env e2

(I think I got that right. You might need to check some variable capture scenarios to be sure.)

Upvotes: 2

Related Questions