Jump to content

Metaprogramming: Difference between revisions

(Fixed typos.)
Line 58:
* E program fragments may be quoted, manipulated as an AST, and evaluated, similarly to Lisp; lexical environments are first-class objects (though static with respect to the evaluated code). Demonstrated in [[Runtime evaluation#E]] and [[Eval in environment#E]].
* Control structures may be defined, as demonstrated in [[Extend your language#E]].
 
=={{header|Common Lisp}}==
 
We can use Lisp macros, and other features, to add support to Lisp for monads, which come from functional languages. The following module of code provides a new macro form called COMPREHEND which works with monads. If we use the LIST monad, we get list comprehensions. For instance:
 
<lang lisp>
;; The -> notation is not part of Lisp, it is used in examples indicate the output of a form.
;;
;;
(comprehend 'list-monad (cons x y) (x '(1 2 3)) (y '(A B C)))
 
-> ((1 . A) (1 . B) (1 . C)
(2 . A) (2 . B) (2 . C)
(3 . A) (3 . B) (3 . C))</lang>
 
As you can see, the comprehension processes all combinations of X and Y from both sets, and collects the application of (CONS X Y) to these elements.
 
In other words {(cons x y) | x &isin; { 1, 2 ,3 } &and; y &isin; { A, B, C }}
 
Other monads are possible: idenitity, state transfomer, etc. Some of these are provided in the code below.
 
Furthermore, a form called DEFINE-MONAD is provided to define new kinds of monads. It is used to define the basic monads. DEFINE-MONAD also optionally generates a (trivial) short-hand comprehension macro for your monad type. So instead of (comprehend 'list ...) it is possible to write is also (list-comp ...).
 
Note how the state transformer monad uses the identity monad comprehension in its definition.
 
Also, a monad is a class, and there is a way in the DEFINE-MONAD syntax to declare what the base classes are (multiple inheritance) as well as any additional custom slots.
 
To see the original version of this code with lengthy comments, have a look in the Lisp Pastebin. http://paste.lisp.org/display/71196
 
<lang lisp>(defgeneric monadic-map (monad-class function))
 
(defgeneric monadic-join (monad-class container-of-containers &rest additional))
 
(defgeneric monadic-instance (monad-class-name))
 
(defmacro comprehend (monad-instance expr &rest clauses)
(let ((monad-var (gensym "CLASS-")))
(cond
((null clauses) `(multiple-value-call #'monadic-unit
,monad-instance ,expr))
((rest clauses) `(let ((,monad-var ,monad-instance))
(multiple-value-call #'monadic-join ,monad-var
(comprehend ,monad-var
(comprehend ,monad-var ,expr ,@(rest clauses))
,(first clauses)))))
(t (destructuring-bind (var &rest container-exprs) (first clauses)
(cond
((and var (symbolp var))
`(funcall (monadic-map ,monad-instance (lambda (,var) ,expr))
,(first container-exprs)))
((and (consp var) (every #'symbolp var))
`(multiple-value-call (monadic-map ,monad-instance
(lambda (,@var) ,expr))
,@container-exprs))
(t (error "COMPREHEND: bad variable specification: ~s" vars))))))))
 
(defmacro define-monad (class-name
&key comprehension
(monad-param (gensym "MONAD-"))
bases slots initargs
((:map ((map-param)
&body map-body)))
((:join ((join-param
&optional
(j-rest-kw '&rest)
(j-rest (gensym "JOIN-REST-")))
&body join-body)))
((:unit ((unit-param
&optional
(u-rest-kw '&rest)
(u-rest (gensym "UNIT-REST-")))
&body unit-body))))
`(progn
(defclass ,class-name ,bases ,slots)
(defmethod monadic-instance ((monad (eql ',class-name)))
(load-time-value (make-instance ',class-name ,@initargs)))
(defmethod monadic-map ((,monad-param ,class-name) ,map-param)
(declare (ignorable ,monad-param))
,@map-body)
(defmethod monadic-join ((,monad-param ,class-name)
,join-param &rest ,j-rest)
(declare (ignorable ,monad-param ,j-rest))
,@join-body)
(defmethod monadic-unit ((,monad-param ,class-name)
,unit-param &rest ,u-rest)
(declare (ignorable ,monad-param ,u-rest))
,@unit-body)
,@(if comprehension
`((defmacro ,comprehension (expr &rest clauses)
`(comprehend (monadic-instance ',',class-name)
,expr ,@clauses))))))
 
(defmethod monadic-map ((monad symbol) function)
(monadic-map (monadic-instance monad) function))
 
(defmethod monadic-join ((monad symbol) container-of-containers &rest rest)
(apply #'monadic-join (monadic-instance monad) container-of-containers rest))
 
(defmethod monadic-unit ((monad symbol) element &rest rest)
(apply #'monadic-unit (monadic-instance monad) element rest))
 
(define-monad list-monad
:comprehension list-comp
:map ((function) (lambda (container) (mapcar function container)))
:join ((list-of-lists) (reduce #'append list-of-lists))
:unit ((element) (list element)))
 
(define-monad identity-monad
:comprehension identity-comp
:map ((f) f)
:join ((x &rest rest) (apply #'values x rest))
:unit ((x &rest rest) (apply #'values x rest)))
 
(define-monad state-xform-monad
:comprehension state-xform-comp
:map ((f)
(lambda (xformer)
(lambda (s)
(identity-comp (values (funcall f x) new-state)
((x new-state) (funcall xformer s))))))
:join ((nested-xformer)
(lambda (s)
(identity-comp (values x new-state)
((embedded-xformer intermediate-state)
(funcall nested-xformer s))
((x new-state)
(funcall embedded-xformer intermediate-state)))))
:unit ((x) (lambda (s) (values x s))))</lang>
 
=={{header|J}}==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.