LISP - 通过其参数搜索特定功能的程序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LISP - 通过其参数搜索特定功能的程序相关的知识,希望对你有一定的参考价值。

对于课程项目,我必须在lisp中编写一个程序。

该程序应包含最重要的lisp函数,它们的输入和输出参数以及可选参数。

例如:function - first,input - list,output - object(list的第一个成员)。

该计划应以两种不同的方式运作:

  1. 你给程序一个函数的名称,它应该返回函数参数。
  2. 输入函数参数,如果存在具有这些参数的函数,则应返回函数的名称。

我的问题:

  1. 在lisp中处理这样的任务的正确方法是什么?我想也许一棵树可以处理它? (制作一个包含所有函数和参数的树,然后编写一个处理它的程序)。
  2. 有没有人有更好的想法来接近这个任务?或者一些建议在哪里/如何开始?或包含任何信息的教程?

目前我有点迷失如何开始。您将给予的任何帮助将非常感谢。

英语不是我的第一语言,所以我希望一切都是可以理解的。

问候。

答案

首先看一下准备常见的lisp开发环境。在那之后我认为你应该调查:

和那样的事情。看看两个常见的lisp函数:

这是一个小例子:

CL-USER> (defun my-sum (a b) "Add my-sum parameters A and B." (+ a b))
MY-SUM
CL-USER> (my-sum 2 3)
5 (3 bits, #x5, #o5, #b101)
CL-USER> (describe #'my-sum)
#<FUNCTION MY-SUM>
  [compiled function]


Lambda-list: (A B)
Derived type: (FUNCTION (T T) (VALUES NUMBER &OPTIONAL))
Documentation:
  Add my-sum parameters A and B.
Source form:
  (SB-INT:NAMED-LAMBDA MY-SUM
      (A B)
    "Add my-sum parameters A and B."
    (BLOCK MY-SUM (+ A B)))
; No values
CL-USER> (documentation 'my-sum 'function)
"Add my-sum parameters A and B."
CL-USER> (defun my-sum (a b) "Add my-sum parameters A and B." (declare (type fixnum a b)) (+ a b))
WARNING: redefining COMMON-LISP-USER::MY-SUM in DEFUN
MY-SUM
CL-USER> (describe #'my-sum)
#<FUNCTION MY-SUM>
  [compiled function]


Lambda-list: (A B)
Derived type: (FUNCTION (FIXNUM FIXNUM)
               (VALUES
                (INTEGER -9223372036854775808 9223372036854775806)
                &OPTIONAL))
Documentation:
  Add my-sum parameters A and B.
Source form:
  (SB-INT:NAMED-LAMBDA MY-SUM
      (A B)
    "Add my-sum parameters A and B."
    (DECLARE (TYPE FIXNUM A B))
    (BLOCK MY-SUM (+ A B)))
; No values

最后,最后一个提示使用describe的输出中的字符串:

CL-USER> (with-output-to-string (*standard-output*)
               (describe #'my-sum))
"#<FUNCTION MY-SUM>
  [compiled function]


Lambda-list: (A B)
Derived type: (FUNCTION (FIXNUM FIXNUM)
               (VALUES
                (INTEGER -9223372036854775808 9223372036854775806)
                &OPTIONAL))
Documentation:
  Add my-sum parameters A and B.
Source form:
  (SB-INT:NAMED-LAMBDA MY-SUM
      (A B)
    "Add my-sum parameters A and B."
    (DECLARE (TYPE FIXNUM A B))
    (BLOCK MY-SUM (+ A B)))
"
另一答案

从表面上看,任务似乎是在内存中构建一个简单的符号数据库,可以通过两种方式进行搜索。数据库中的条目被理解为功能。 “输出参数”可以理解为一个或多个返回值。这些东西没有在ANSI Lisp中命名。对任务的有用解释是无论如何都给出返回值符号标签。此外,我们也许可以使用类型符号作为返回值以及参数。因此,例如,cons函数的数据库条目可能如下所示:

(cons (t t) cons)   ;; function named cons takes two objects, returns a cons

类型t是ANSI Lisp中所有类型的超类型;它意味着“任何价值”。

这些记录的列表可以放入一些全局变量中。然后我们编写一个名为get-params-by-name的函数,这样:

(get-params-by-name 'cons) -> (t t)

另一个:get-names-by-params

(get-names-by-params '(t t)) -> (cons)

此函数作为列表返回所有匹配的函数。多个函数可以具有此签名。

然后诀窍是找到可选和休息参数的良好表示。它可能与语言使用的符号相同:

(list (&rest t) list)   ;; list takes rest arguments of any type, returns list

由于我们只对完全匹配感兴趣,因此我们不必实际解析&rest表示法。当用户通过参数查询时,他们的查询对象将以字面上的(&rest t),在相同的语法中。

equal函数可用于判断两个符号列表是否相同:

(equal '(&rest t) '(&rest t)) -> t
(equal '(t t) '(t t)) -> nil

所以练习并不困难:只需通过列表进行映射,寻找匹配。

(defun get-name-by-params (database params)
  (let ((matching-entries (remove-if-not (lambda (entry)
                                            (equal (second entry) params))
                                          database)))
    (mapcar #'first matching-entries))) ;; just the names, please

这里,该函数将数据库列表作为参数,而不是引用全局变量。我们集成它的整个程序可以提供替代接口,但这是我们的低级查找功能。

测试:

[1]> (get-name-by-params '((cons (t t) cons) (list (&rest t) list)) '(integer string))
NIL
[3]> (get-name-by-params '((cons (t t) cons) (list (&rest t) list)) '(t t))
(CONS)
[4]> (get-name-by-params '((cons (t t) cons) (list (&rest t) list)) '(&rest t))
(LIST)

在作业到期之前,我会向导师澄清这是否是对模糊要求的正确解释。

另一答案

鉴于这是一个课程项目,我将提供一个不完整的答案,让你填补空白。

该计划应该做什么

我对你被要求做的事情的解释是提供一个实用的工具

  • 给定函数的名称返回其参数列表(在下面称为“lambda列表”);
  • 给定一个lambda列表返回该lambda列表的所有函数。

所以,首先你需要决定两个lambda列表是否相同。作为一个例子,(x)(y)一样,作为lambda列表?是的,它是:形式参数的名称仅在函数的实现中起作用,并且通常不会知道它们:这两个lambda列表都意味着“一个参数的函数”。

interestring的东西是各种类型的可选参数:(a &optional b)显然与(a)不同,但与(b &optional c)相同,但它与(a &optional (b 1 bp))相同吗?在这段代码中,我说是的,它是相同的:可选参数的默认值和当前参数不会改变lambda列表是否相同。那是因为这些都是函数的实现细节。

一套

我们将它放入一个包中,以便清楚界面是什么:

(defpackage :com.stackoverflow.lisp.fdesc-search
  (:use :cl)
  (:export
   #:defun/recorded
   #:record-function-description
   #:clear-recorded-functions
   #:name->lambda-list
   #:lambda-list->names))

(in-package :com.stackoverflow.lisp.fdesc-search)

记录信息

因此,首先我们需要一种记录功能信息的机制。我们将使用像defun这样的宏来记录信息,我将其称为defun/recorded。我们希望能够在程序存在之前记录有关事物的信息,并且我们通过在列表中使用defun/recorded存储“待定”记录来执行此操作,一旦程序存在,它将启动并正确记录。这让我们在整个代码中使用defun/recorded

;;; These define whether there is a recorder, and if not where pending
;;; records should be stashed
;;;
(defvar *function-description-recorder* nil)
(defvar *pending-function-records* '())

(defmacro defun/recorded (name lambda-list &body forms)
  "Like DEFUN but record function information."
  ;; This deals with bootstrapping by, if there is not yet a recording
  ;; function, stashing pending records in *PENDING-FUNCTION-RECORDS*,
  ;; which gets replayed into the recorder at the point it becomes
  ;; available.
  `(progn
     ;; do the DEFUN first, which ensures that the LAMBDA-LIST is OK
     (defun ,name ,lambda-list ,@forms)
     (if *function-description-recorder*
         (progn
           (dolist (p (reverse *pending-function-records*))
             (funcall *function-description-recorder*
                      (car p) (cdr p)))
           (setf *pending-function-records* '())
           (funcall *function-description-recorder*
                    ',name ',lambda-list))
       (push (cons ',name ',lambda-list)
             *pending-function-records*))
     ',name))

匹配lambda列表,第一步

现在我们希望能够匹配lambda列表。因为我们显然要在某种树中存储由lambda列表索引的东西,所以我们只需要能够处理它们的匹配元素。而且(见上文)我们并不关心默认值这样的事情。我选择这样做首先简化lambda列表以删除它们然后匹配简化元素:还有其他方法。

simplify-lambda-list做了简化,argument-matches-p告诉你两个参数是否匹配:有趣的是它需要知道lambda list关键字,它必须完全匹配,而其他所有东西都匹配。 lambda-list-keywords常数由CL标准方便地提供。

(defun/recorded simplify-lambda-list (ll)
  ;; Simplify a lambda list by replacing optional arguments with inits
  ;; by their names.  This does not validate the list
  (loop for a in ll
        collect (etypecase a
                  (symbol a)
                  (list (first a)))))

(defun/recorded argument-matches-p (argument prototype)
  ;; Does an argument match a prototype.
  (unless (symbolp argument)
    (error "argument ~S isn't a symbol" argument))
  (unless (symbolp prototype)
    (error "prototype ~S isn't a symbol" prototype))
  (if (find-if (lambda (k)
                 (or (eq argument k) (eq prototype k)))
               lambda-list-keywords)
      (eq argument prototype)
    t))

功能描述(部分)

有关函数的信息存储在名为fdescs的对象中:这里没有给出这些对象的定义,但我们需要回答的一个问题是“两个fdescs是指同一函数的版本吗?”好吧,如果函数的名称相同,它们就会这样做。请记住,函数名称不必是符号(允许使用(defun (setf x) (...) ...)),因此我们必须与equal进行比较而不是eql

(defun/recorded fdescs-equivalent-p (fd1 fd2)
  ;; do FD1 & FD2 refer to the same function?
  (equal (fdesc-name fd1)
      

以上是关于LISP - 通过其参数搜索特定功能的程序的主要内容,如果未能解决你的问题,请参考以下文章

Common Lisp宏中的词法绑定

python10

何时在 clojure(或 lisp)中使用感叹号?

Lisp家族迎来新成员,函数式语言Lux是什么?

lisp中 boundp函数啥意思

如何在recyclerview中使用编辑文本进行搜索?