LISP Как создать базу данных, хранящую параметры функции - PullRequest
2 голосов
/ 18 марта 2019

Маленькая программа на lisp, которую я написал, должна сделать следующее (скопировано из моего старого вопроса: LISP - Программа для поиска конкретной функции по ее параметрам ):

Программа должна работать 2 разными способами:

  1. Вы даете программе имя функции, и она должна возвращать параметры функции.

  2. Вы вводите параметры функции и, если функция с этими параметрами существует, она должна вернуть имя функции.

Я получил следующий код:

(defun get-name-by-params (database params)
  (let ((matching-entries (remove-if-not (lambda (entry)
                                            (equal (second entry) params))
                                          database)))
    (mapcar #'first matching-entries)))



(defun get-params-by-name (database function)
  (let ((matching-entries (remove-if-not (lambda (entry)
                                            (equal (first entry) function))
                                          database)))
    (flatten(mapcar #'second matching-entries))))


(defun flatten (L)
    (if (null L)
        nil
        (if (atom (first L))
            (cons (first L) (flatten (rest L)))
            (append (flatten (first L)) (flatten (rest L))))))

С этим кодом я получаю следующие результаты:

(get-params-by-name '((cons (t t) cons) (list (&rest t) list) (append (&rest lists) result)) 'append)
->(&REST LISTS)

(get-name-by-params '((cons (t t) cons) (list (&rest t) list)) '(&rest t))
->(LIST)

Это в обоих случаях именно то, что мне нужно. Моя последняя проблема с моей задачей заключается в том, что мне нужно создать базу данных, в которой хранятся функции и параметры, потому что мне нужно будет добавить еще много функций в программу.

Так что мне нужно создать базу данных, которая хранит следующие данные

'((cons (t t) cons) (list (&rest t) list) (append (&rest lists) result))

и, если возможно, могут быть обработаны данными функциями.

Может кто-нибудь дать мне пример того, как создать базу данных для этой задачи?

Ответы [ 2 ]

0 голосов
/ 23 марта 2019

Вы можете создать базу данных на Лиспе вместо использования базы данных постоянного хранения, и вы можете сохранить данные в сериализованном формате для загрузки / сохранения базы данных. Вы были бы удивлены, но некоторые крупные компании, такие как Yahoo! сделал это в 90-х годах, и многие до сих пор делают это сегодня, вместо использования постоянной базы данных, такой как MySQL. Вот пример структуры программы, если вы хотите написать базу данных на Лиспе. Вы можете использовать CLOS для хранения функций как экземпляров этого класса. Вы говорите, что вам нужно имя функции и параметры функции. Таким образом, вы можете создать класс с атрибутами «имя» и «параметры». Вот пример:

 (defclass functions()
   ((name :accessor func-name
      :initarg :name)
    (params :accessor func-params
        :initarg :params
        :initform '(nil))))

Мы можем создать класс со слотами для имени и параметров, как я показал выше, а затем мы можем создать экземпляры этого класса. Так что, если, например, у меня есть такая функция:

(defun foo (n lst)
    (list foo))

Я могу создать экземпляр, подобный этому ...

 (defvar func-1 (make-instance 'functions
                   :name "foo"
                   :params '("n" "lst")))

И если у меня есть такая функция:

(defun foo-2(lst n)
    (list lst n))

Я могу создать еще один экземпляр, подобный этому:

(defvar func-2 (make-instance 'functions
                   :name "foo-2"
                   :params '("lst" "n")))

Теперь, как мы храним эти экземпляры в базе данных? У нас есть несколько вариантов, но простой и общий пример будет хранить экземпляры в списке. Мы могли бы увеличить сложность или даже создать собственную форму встроенного языка SQL с помощью макросов, но для простоты мы можем просто использовать список и функцию find для создания базы данных make-shift. Вот пример базы данных и двух функций для поиска в этой базе данных по имени функции или параметрам:

(defvar *func-db* nil) ;Create an empty list to store the functions
(push func-1 *func-db*)
(push func-2 *func-db*) ;Push a couple of functions to the DB

(defun find-params (name)
   (func-params
    (find name *func-db*
      :test #'string-equal
      :key #'func-name)))

(defun find-name (param-list)
   (func-name 
    (find param-list *func-db*
      :test #'equal
      :key #'func-params))

Теперь мы можем создать пару функций, чтобы найти параметры функции на основе имени, которое мы ищем, или найти имя функции на основе введенных нами параметров. Я буду использовать строки в этом сценарии для простой иллюстрации, но вам, вероятно, следует использовать символы. Вот несколько примеров того, как мы будем искать в БД:

CL-USER> (find-params "foo")
("n" "lst")
CL-USER> (find-params "foo-2")
("lst" "n")
CL-USER> (find-name '("n" "lst"))
"foo"
CL-USER> (find-name '("lst" "n"))
"foo-2"

Именно так мы можем создать временную базу данных на Лиспе. Хорошая книга для чтения - «Практический общий Лисп». Есть бесплатная онлайн-версия, и в этой книге один из главных проектов - создание базы данных MP3. Самый простой пример - использование списка для хранения информации, а затем ее поиск. Если вы хотите сохранить базу данных для дальнейшего использования, вы можете сохранить ее в файл, а затем загрузить, когда захотите использовать ее снова. Этот метод может показаться простым, но я видел, как крупные компании используют его против MySQL. Вы даже можете создать свой собственный встроенный язык SQL для поиска информации, и, поскольку информация хранится в памяти, она может получать результаты даже быстрее, чем MySQL, если вы решили расширить этот проект и создать веб-приложение на Лиспе.

0 голосов
/ 22 марта 2019

Для экспериментальных и быстрых проектов я склонен использовать простой текстовый файл, в котором просто хранится s-выражение.

Очень простая база данных:

(format open-file-stream "~S" any-sexp)

Вы можете искать запись, используя несколько простых функций.

Для поиска по (неявному) индексу :

(defun read-nth-sexp (n file)
  (with-open-file 
    (file-stream file) 
    (loop for i from 0 
      for sexp = (read file-stream nil)
      do (if (eq n i) (return sexp)))))

Найтипо ключу : (Примечание. Вы сохраняете ключ, просто добавляя его к sexp в любом месте в структуре sexp, когда сохраняете его. Позже вы можете получить его, предоставив соответствующий селекторфункция, по умолчанию предполагается, что #'car.)

(defun find-entry (entry file &key (select #'car))
  (with-open-file 
    (file-stream file) 
    (loop for sexp = (read file-stream nil)
      while sexp
      do (if (equal (funcall select sexp) entry)
             (return sexp)))))

Это хорошо работает для записей до 10000 или, возможно, 100000, в зависимости от вашего оборудования.У меня были трудности с чем-либо, превышающим полмиллиона записей.


У меня не было необходимости обновлять свои данные, поэтому я никогда не писал никаких функций обновления, но их можно было легко написать.

Для очень быстрого поиска у меня был успех с двоичным поиском, при условии, конечно, что ваши данные имеют сортируемые свойства.

...