Student
Student

Reputation: 719

Typed lambda functions in Common Lisp

I don't know of any practical uses for this, it just came to my mind whether there is any thing comparable to defmethod to defun for lambda? Something like this

(defmacro tlambda (args &body body)
  (let* ((gf-name (subseq (write-to-string (gensym)) 2))
         (gf-sym (read-from-string gf-name)))
    `(progn (defmethod ,gf-sym ,args ,@body)
        (prog1 (symbol-function ',gf-sym) (unintern ',gf-sym)))))

(tlambda ((x fixnum)))          ;#<STANDARD-GENERIC-FUNCTION #:G759 (1)>
(funcall (tlambda ((x fixnum)) (* x 2)) 4) ;8
(funcall (tlambda ((x list)) (second x)) '(a s d f)) ;S
(funcall (tlambda ((x string)) (string-upcase x)) "lambda") ;"LAMBDA"

Upvotes: 1

Views: 175

Answers (2)

user5920214
user5920214

Reputation:

I agree with Svante that you probably don't want this. But if you did want it the way you are doing it is very confused: I simply don't understand what you are doing with gf-sym and gf-name but it represents some quite serious confusion about symbols I think (and is almost certainly unsafe). Instead you could do something like this:

(defmacro tlambda (&body cases)
  (let* ((gf-name (gensym)))
    `(progn
       ,@(mapcar (lambda (case)
                   `(defmethod ,gf-name ,@case))
                 cases)
       (symbol-function ',gf-name))))

And now

> (let ((l (tlambda
             ((x y) (cons x y))
             ((x (y integer))
              (declare (ignore x)) y))))
    (values (funcall l 'a 'b)
            (funcall l 'a 1)))
(a . b)
1

I'm not sure whether the objects created by tlambda can be garbage-collected: it may be they can.

Upvotes: 0

Svante
Svante

Reputation: 51501

I do not think that this makes sense in the shape you show. What should happen if the type doesn't match? If you just want to check types, use check-type.

Defmethod and defun are not really comparable, by the way. Defun registers a function, while defmethod adds a method to an existing (though maybe implicitly created) generic function. The types that you use in a method definition are used to dispatch (runtime polymorphism) to the right method upon invocation of the generic function. The mechanisms for this dispatch are a bit expensive when constructed, so you probably shouldn't try to do that on the fly (something like a generic-lambda) or transiently (something like a method-let).

Instead, use (e/c)typecase and similar for ad hoc dispatch, and check-type for checking types. There are also libraries for pattern-based polymorphism (e. g. optima, trivia), which you could use for more elaborate cases.

Upvotes: 3

Related Questions