2012-01-06 29 views
5

Có cách nào để tạm nhập một vài hàm từ gói vào gói hiện tại, sử dụng các hàm/macro phổ biến tiêu chuẩn không?Lisp thường gặp: Phương pháp tốt nhất để tạm nhập một vài chức năng từ gói

Tôi không thể tìm thấy và phải tự cuộn. Tôi không muốn mã hóa bất cứ điều gì, hoặc giới thiệu một cấu trúc ngôn ngữ khác, nếu tiêu chuẩn đã cung cấp chức năng như vậy.

(defmacro with-functions (functions the-package &body body) 
    "Allows functions in the-package to be visible only for body. 
    Does this by creating local lexical function bindings that redirect calls 
    to functions defined in the-package" 
    `(labels 
    ,(mapcar (lambda (x) `(,x (&rest args) 
           (apply (find-symbol ,(format nil "~:@(~a~)" x) 
                ,the-package) 
             args))) 
       functions) 
    ,@body)) 

Ví dụ sử dụng:

(defclass-default test-class() 
    ((a 5 "doc") 
    (b 4 "doc"))) 
#<STANDARD-CLASS TEST-CLASS> 
CL-USER> 
(with-functions (class-direct-slots slot-definition-name) 'sb-mop 
    (with-functions (slot-definition-initform) 'sb-mop 
    (slot-definition-initform 
     (car (class-direct-slots (find-class 'test-class)))))) 
5 
CL-USER> 

EDIT: Thành lập một số gợi ý Rainer để vĩ mô.

Tôi quyết định giữ khả năng tra cứu thời gian chạy, tại thời điểm tra cứu thời gian chạy để tìm hàm trong gói.

Tôi đã cố gắng viết macro nhập có sử dụng tính năng nhập bóng và không phổ biến, nhưng tôi không thể làm cho nó hoạt động. Tôi đã có vấn đề với người đọc nói rằng các chức năng nhập khẩu đã không tồn tại được (tại thời gian đọc) trước khi mã nhập khẩu các chức năng đã được đánh giá.

Tôi nghĩ việc làm việc với tính năng nhập bóng và không truy cập là cách tốt hơn, vì điều này sẽ sạch hơn, nhanh hơn (không có khả năng tra cứu thời gian chạy) và làm việc với các chức năng và biểu tượng trong gói.

Tôi sẽ rất quan tâm để xem liệu ai đó có thể mã hóa macro nhập bằng cách sử dụng tính năng nhập không liên tục và nhập bóng.

+0

này không hoạt động với các hàm từ vựng, vì APPLY không thể gọi chúng bằng các ký hiệu như tên. –

+0

Tôi không nghĩ rằng điều này là có thể với một vĩ mô, bởi vì các biểu tượng được giải quyết bởi người đọc trước khi macro được mở rộng, nhưng tôi có thể sai Tôi chưa hiểu đầy đủ về cách thức hoạt động của trình đọc. – Daimrod

+0

@Daimrod Có thể xây dựng một macro như vậy, nhưng nó rất khó (và, có lẽ, không thể chuyển đổi), bởi vì bạn sẽ phải xử lý xung đột tên, phát sinh từ chiến lược phân giải ký hiệu ban đầu. –

Trả lời

1

Bạn có thể sử dụng import với danh sách các biểu tượng đủ điều kiện (ví dụ: package:symbol hoặc package::symbol) bạn muốn nhập và sau đó unintern chúng.

2

Nó làm cho các cuộc gọi hàm thời gian chạy tốn kém hơn nhiều: nó cung cấp danh sách arg, tra cứu một biểu tượng trong gói, gọi một hàm thông qua ô chức năng của biểu tượng.

Nó chỉ hoạt động thông qua các ký hiệu chứ không phải các hàm từ vựng. Điều đó làm cho nó ít hữu ích hơn trong trường hợp, nơi mã được tạo ra thông qua các macro.

Việc đặt tên của nó gây nhầm lẫn. 'import' là một gói hoạt động và các gói chỉ xử lý các ký hiệu, chứ không phải các hàm. Bạn không thể nhập một hàm trong một gói, chỉ là một biểu tượng.

(labels ((foo() 'bar)) 
    (foo)) 

Tên chức năng từ vựng FOO chỉ trong mã nguồn biểu tượng. Không có cách nào để truy cập chức năng thông qua biểu tượng nguồn của nó sau này (ví dụ bằng cách sử dụng (symbol-function 'foo)). Nếu một trình biên dịch sẽ biên dịch mã trên, nó không cần giữ biểu tượng - nó không cần thiết ngoài mục đích gỡ lỗi. Cuộc gọi của bạn tới APPLY sẽ không tìm thấy bất kỳ chức năng nào được tạo bởi LABELS hoặc FLET.

Macro của bạn không nhập biểu tượng, nó tạo ra một hàm từ vựng cục bộ ràng buộc.

Đối với các macro hơi giống nhau, hãy xem CL:WITH-SLOTSCL:WITH-ACCESSORS. Những người không hỗ trợ tra cứu thời gian chạy, nhưng cho phép biên dịch hiệu quả.

vĩ mô của bạn không làm tổ như thế này (ở đây sử dụng "Clos" như là một gói, giống như "SB-MOP" của bạn):

(defpackage "P1" (:use "CL")) 
(defpackage "P2" (:use "CL")) 

(with-import (p1::class-direct-slots) 'CLOS 
    (with-import (p2::class-direct-slots) 'P1 
    (p2::class-direct-slots (find-class 'test-class)))) 

Các mã được tạo là:

(LABELS ((P1::CLASS-DIRECT-SLOTS (&REST ARGS) 
      (APPLY (FIND-SYMBOL "CLASS-DIRECT-SLOTS" 'CLOS) ARGS))) 
    (LABELS ((P2::CLASS-DIRECT-SLOTS (&REST ARGS) 
      (APPLY (FIND-SYMBOL "CLASS-DIRECT-SLOTS" 'P1) ARGS))) 
    (P2::CLASS-DIRECT-SLOTS (FIND-CLASS 'TEST-CLASS)))) 
+0

Tôi đang gặp sự cố khi hiểu trường hợp sử dụng của bạn. Không nên có bất kỳ ':' trong 'chức năng' arglist. Các hàm arglist có các ký hiệu đại diện cho các tên hàm và gói đó là nơi các hàm đó cư trú. Điều này cũng tương tự như với các khe cắm và có sự truy cập. Tôi nghĩ rằng mã bạn đã viết nên trông giống như: (với-nhập khẩu (lớp-trực tiếp-slots) 'đóng (lớp-trực tiếp-khe (find-class' test-class))) –

+0

@claytontstanley: tại sao không? p1 :: class-direct-slots là tên hàm pháp lý. WITH-SLOTS hoặc WITH-ACCESSORS không có vấn đề gì đối phó với những cái tên như vậy. Ví dụ của tôi cho thấy rằng WITH-IMPORT lồng nhau trong đó một hàm được tạo và sau đó một hàm khác cố gắng sử dụng nó là không thể với macro của bạn. Hãy nhớ rằng: nếu bạn đối phó với các macro Common Lisp, bạn không chỉ viết một cấu trúc được sử dụng bởi người dùng cuối theo cách đơn giản (có giới hạn mà bạn phải ghi và/hoặc kiểm tra), nhưng mọi thứ cũng có thể là một phần của mã phức tạp hơn được tạo bởi các mã khác (-> macro). –

Các vấn đề liên quan