Not logged in. Login

Small Lisp Primitive Function Library in Haskell

This library provides the Haskell representation and implementation of the Small Lisp SExpression type, as well as implementation of each of Small Lisp's built-in primitive library functions.

First recall the algebraic data type for Small Lisp values.

module SExpression where

import Data.Char

data SExpression = NumAtom Int | 
                   SymAtom [Char] | 
                   List [SExpression]

Now we consider how to implement the semantics of Small Lisp primitives such as first, rest, numberp and so on. In general, we provide Haskell functions to implement each primitive. The inputs to the function will be Haskell lists of SExpression values. The output will be of type Maybe SExpression to indicate that calling a Small Lisp primitive may result in an error, that is, whenever the Small Lisp reference manual defines the result as bottom (\(\bot\)).

first [List (a:more)] = Just a
first _ = Nothing

rest [List (a:more)] = Just (List more)
rest _ = Nothing

endp [List []] = Just (SymAtom "T")
endp [List _] = Just (SymAtom "F")
endp _ = Nothing

numberp [NumAtom _]  = Just (SymAtom "T")
numberp _  = Just (SymAtom "F")

symbolp [SymAtom _]  = Just (SymAtom "T")
symbolp _  = Just (SymAtom "F")

listp [List _]  = Just (SymAtom "T")
listp _  = Just (SymAtom "F")

cons [e, List es]  = Just (List (e:es))
cons _  = Nothing

eq [SymAtom n1, SymAtom n2]
    | n1 == n2    = Just (SymAtom "T")
    | otherwise   = Just (SymAtom "F")
eq _ = Nothing

plus [NumAtom n1, NumAtom n2] = Just (NumAtom (n1 + n2))
plus _ = Nothing

minus [NumAtom n1, NumAtom n2] = Just (NumAtom (n1 - n2))
minus _ = Nothing

times [NumAtom n1, NumAtom n2] = Just (NumAtom (n1 * n2))
times _ = Nothing

eqp [NumAtom n1, NumAtom n2]
    | n1 == n2    = Just (SymAtom "T")
    | otherwise   = Just (SymAtom "F")
eqp _ = Nothing

lessp [NumAtom n1, NumAtom n2]
    | n1 < n2    = Just (SymAtom "T")
    | otherwise   = Just (SymAtom "F")
lessp _ = Nothing

greaterp [NumAtom n1, NumAtom n2]
    | n1 > n2    = Just (SymAtom "T")
    | otherwise   = Just (SymAtom "F")
greaterp _ = Nothing

sym_lessp [SymAtom n1, SymAtom n2]
    | n1 < n2    = Just (SymAtom "T")
    | otherwise   = Just (SymAtom "F")
sym_lessp _ = Nothing

explode [SymAtom str] = Just (List (map explode1 str))
explode _ = Nothing

explode1 c
    | isDigit c  = NumAtom (digitToInt c)
    | otherwise  = SymAtom [c]

implode [List (SymAtom (c:chars): more)]
    | isAlpha c  = implodeAlpha (c:chars) more
    | otherwise  = implodeSpecial (c:chars) more
implode _ = Nothing

implodeAlpha str [] = Just (SymAtom str)
implodeAlpha s@(_:_) (SymAtom "-" : (SymAtom (c:chars)): more) 
    | isAlpha c  = implodeAlpha (s ++ ('-':c:chars)) more
    | otherwise  = Nothing
implodeAlpha str@(_:_) (SymAtom "-" : (NumAtom s): more) 
    | s > 0     = implodeAlpha (str ++ ('-':(show s))) more
    | otherwise = Nothing
implodeAlpha str ((SymAtom (c:chars)): more) 
    | isAlpha c  = implodeAlpha (str ++ (c:chars)) more
    | otherwise  = Nothing
implodeAlpha str ((NumAtom s): more) = implodeAlpha (str ++ (show s)) more

implodeSpecial str ((SymAtom (c:chars)): more) 
    | isAlpha c  = Nothing
    | otherwise  = implodeSpecial (str ++ (c:chars)) more
implodeSpecial _ _ = Nothing

divide [NumAtom n1, NumAtom 0] = Nothing
divide [NumAtom n1, NumAtom n2] = 
    Just (NumAtom (truncate (fromIntegral n1 / (fromIntegral n2))))
divide _ = Nothing

rem [NumAtom n1, NumAtom 0] = Nothing
rem [NumAtom n1, NumAtom n2] = 
    Just (NumAtom (n1 - (n2 * (truncate (fromIntegral n1 / (fromIntegral n2))))))
rem _ = Nothing

Showing S-Expressions

instance Show SExpression where
    show (NumAtom n) = (show n)
    show (SymAtom s) = s
    show (List []) = "()"
    show (List (a:s)) = "(" ++ show a ++ (concatMap ((' ':) . show) s) ++ ")"
Updated Thu Oct. 25 2018, 12:02 by cameron.