11
\$\begingroup\$

Background:
This began with James Colgan's Lisp-Dojo for Ruby. My implementation can be found here. I then moved on to Write yourself a scheme in 48 hours. This question has to do with one of the implementation decisions.

Code:

My implementation of eval

--# The eval function takes a scope and paresed Lisp value and
--# returns the resulting Lisp Value.
--# String, Number and Bool return themselves.
--# An Atom trys to find its self in the scope and retrun that value
--# A List is evaluated using the normal Lisp rules.
eval :: LispScope-> LispVal -> IOThrowsError LispVal
eval s val@(String _) = return val
eval s (Atom val) = do
 (liftIO $ getValue s val) >>= maybe (throwError $ "Value not in scope: " ++ val) (return)
eval s val@(Number _) = return val
eval s val@(Bool _) = return val
eval scope (List (fn:lvs)) = do
 fun <- eval scope fn
 case fun of 
 Syntax f _-> f scope lvs
 Function f _-> evalMap scope lvs >>= f
 val -> throwError $ (show val) ++ " is not a function"
eval scope (List []) = return $ List []
eval _ badForm = throwError $ "Unrecognized form: " ++ show badForm

Note two things: 1) I do not refer to any special forms, 2) the use of Syntax for hygenic forms.

This is a piece of code from Write yourself a scheme in 48 hours:

--# evaluate the "if" form
eval (List [Atom "if", pred, conseq, alt]) = 
 do result <- eval pred
 case result of
 Bool False -> eval alt
 otherwise -> eval conseq

Note that in the tutorial the form is written directly into the eval function. This pattern is followed for other syntaxes like define and lambda.

Question: When I implemented my version I followed what I thought was a wise choice demonstrated in James Colgan's solution to the lisp-dojo to keep eval as simple as possible and instead to push the syntax implementations into the root scope. eg:

ifSyntax :: LispScope -> [LispVal] -> IOThrowsError LispVal
ifSyntax s [pred, consequent, alternate] = do
 pred' <- eval s pred
 case pred' of 
 Bool False -> eval s alternate
 otherwise -> eval s consequent
ifSyntax _ _ = throwError "if: Bad Syntax"
ifVal = (Syntax ifSyntax $ Left "syntax (if)")
--# this is then added to the initial scope

I would like to know why one choice might be better then the other, and what is typical in real-world implementations.

Reference:

My definition of the LispVal data type:

type LispScope = Scope LispVal
data Lambda = Lambda {params :: [String], body :: [LispVal]}
data LispVal = Atom String
 | List [LispVal]
 | Number Integer
 | Real Double
 | String String
 | Function ([LispVal] -> IOThrowsError LispVal) (Either String Lambda)
 | Syntax (LispScope -> [LispVal] -> IOThrowsError LispVal) (Either String Lambda)
 | Bool Bool
 | Port Handle
asked Apr 20, 2011 at 15:53
\$\endgroup\$

1 Answer 1

8
\$\begingroup\$

When I went through the WYAS48 I made the same decision of breaking the bits of eval off into smaller functions. I found this made testing easier since I could focus on just one function at a time.

I find that having a function be one massive bunch of logic is not helpful. In an imperative language the equivalent would be a single function with a ton of if/else or case/switch logic. Whenever I see that I tend to break things off into more manageable functions.

The issue that tends to happen is the little functions need some kind of state from the original big function. Finding this out and resolving it can be difficult at times and others just plain messy. The code is often better for it in the end.

answered May 8, 2014 at 19:24
\$\endgroup\$
1
  • 5
    \$\begingroup\$ Congratulations! You are officially a zombie killer! Well done! \$\endgroup\$ Commented May 8, 2014 at 19:30

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.