\section{Booleans} Booleans are about the simplest possible type you could think of. <>= <> <> <> @ <>= (in-package :max) @ Create an enumerated type to implement booleans. <>= (defparameter *boolean-type* (make-type :key 'BOOLEAN)) (add-init-hook #'(lambda () (add-name *boolean-type* "boolean"))) @ Create values in the boolean type for true and false using the interface to enumerated types, MAKE-ADDRESS. Return the addresses, and store those addresses in global variables named TRUE and FALSE. LISP uses T and NIL and doesn't define the more natural names in this case. Booleans are common enough that they don't need *'s around them, hopefully. <>= (defparameter TRUE (make-address *boolean-type* :key 'TRUE)) (defparameter GET-TRUE (make-function 'builtin-function *null-type* *boolean-type* #'(lambda (ignore-nil) TRUE) )) (defparameter FALSE (make-address *boolean-type* :key 'FALSE)) (defparameter GET-FALSE (make-function 'builtin-function *null-type* *boolean-type* #'(lambda (ignore-nil) FALSE) )) (add-init-hook #'(lambda () (add-public-function get-true) (add-name get-true "true") (add-public-function get-false) (add-name get-false "false") (add-name true "true") (add-name false "false") )) @ \subsection{Boolean functions} Booleans make a good example for creating new functions. Since we only recently created product types, we haven't yet added any multi-argument functions. There's only two non-trivial single-argument functions on booleans (the trivial ones just return TRUE or FALSE and ignore their argument, so we don't implement those): <>= <> <> @ \subsubsection{Boolean NOT} Now the actual definition that you've all been waiting for. MAKE-FUNCTION doesn't use any keyword arguments, so take care with the order of the 5 arguments (or just copy this definition when you create a new enumerated function). <>= (defparameter boolean-not (make-function 'enumerated-function *boolean-type* *boolean-type* (function-values '(true . false) '(false . true) ) 'BOOLEAN-NOT ) ) (add-init-hook #'(lambda () (add-public-function boolean-not) (add-name boolean-not "not") )) @ \subsubsection{Boolean identity} Now we do the same thing for the identity function. \footnote{Identity functions are kind of cool, since you can specialize them to get all the functions that have no argument and return a value in the type. Alas, we can't do that yet. Max will have generalization and specialization of functions in a later iteration.} @ Since we can't automatically build this type definition from the tests yet, we have to manually specify it! <>= (defparameter boolean-identity (make-function 'enumerated-function *boolean-type* *boolean-type* (function-values '(true . true) '(false . false) ) 'BOOLEAN-IDENTITY ) ) (add-init-hook #'(lambda () (add-public-function boolean-identity) )) @ Return the appropriate Max boolean value depending on whether the given LISP function evaluates to NIL or non-NIL. TODO: rewrite as a macro <>= (defun boolean-cond (lisp-func) (if (funcall lisp-func) TRUE FALSE) ) @ AND and OR. <>= (add-init-hook #'(lambda () (let ((boolean-and (make-function 'builtin-function (type-product *boolean-type* *boolean-type*) *boolean-type* #'(lambda (twobools) (let ((vals (product-values twobools))) (boolean-cond #'(lambda () (and (addr-equal TRUE (first vals)) (addr-equal TRUE (second vals)) ) )) ) ))) (boolean-or (make-function 'builtin-function (type-product *boolean-type* *boolean-type*) *boolean-type* #'(lambda (twobools) (let ((vals (product-values twobools))) (boolean-cond #'(lambda () (or (addr-equal TRUE (first vals)) (addr-equal TRUE (second vals)) ) )) ) ))) ) (add-public-function boolean-and) (add-public-function boolean-or) (add-name boolean-and "and") (add-name boolean-or "or") ) )) @