Lisp:使用语法糖访问递归哈希

JEP*_*ice 2 lisp common-lisp

我正在尝试构建一个函数(或宏)来简化哈希表中数据的获取和设置(意思是哈希内的哈希,哈希内的哈希等)。我不认为我可以使用宏来实现,而且我不确定如何使用eval来实现。我希望能够执行以下操作:

(gethashdeep *HEROES* "Avengers" "Retired" "Tony Stark")
Run Code Online (Sandbox Code Playgroud)

并得到回报“钢铁侠”

散列都是通过以下方式创建的:

(setf hashtablename (make-hash-table :test 'equal))
Run Code Online (Sandbox Code Playgroud)

然后从那里开始

我可以执行以下操作,但是想要对其进行抽象,以便可以从任意深度以编程方式提取值:

;;pulling from a hash that's 2 deep
(gethash "Tony Stark" (gethash "Avengers" *HEROES*))
Run Code Online (Sandbox Code Playgroud)

更新-我的努力:

(defun getdeephash (hashpath h k)
  (let* ((rhashpath (reverse hashpath))
    (hashdepth (list-length hashpath))
    (hashcommand (concatenate 'string "(gethash \"" k "\"")))
   (loop for i from 1 to hashdepth
      do (setf hashcommand (concatenate 'string hashcommand "(gethash \"" (nth (- i 1) rhashpath) "\"")))
      (setf hashcommand (concatenate 'string  hashcommand " "  h (make-string (- hashdepth 0) :initial-element #\Right_Parenthesis) ")"))
      (values hashcommand)))
Run Code Online (Sandbox Code Playgroud)

Xac*_*ach 8

嵌套表查找不需要花哨的东西。

一种可能的定义gethash-deep

(defun gethash-deep (value &rest keys)
  (if (or (endp keys)
          (not (hash-table-p value)))
      value
      (apply #'gethash-deep
             (gethash (first keys) value)
             (rest keys))))
Run Code Online (Sandbox Code Playgroud)

使用示例:

(defun table (&rest keys-and-values &key &allow-other-keys)
  (let ((table (make-hash-table :test 'equal)))
    (loop for (key value) on keys-and-values by #'cddr
          do (setf (gethash key table) value))
    table))

(defparameter *heroes*
  (table "Avengers"
         (table "Retired" (table "Tony Stark" "Iron Man")
                "Active" (table "Bruce Banner" "Hulk"))))

(gethash-deep *heroes* "Avengers" "Retired" "Tony Stark") => "Iron Man"
(gethash-deep *heroes* "Avengers" "Active" "Bruce Banner") => "Hulk"
Run Code Online (Sandbox Code Playgroud)


Ehv*_*nce 8

这是Access库的一个衬里:

(ql:quickload "access")
Run Code Online (Sandbox Code Playgroud)

我们定义*heroes*哈希表(如Xach的示例):

(defun table (&rest keys-and-values &key &allow-other-keys)
  (let ((table (make-hash-table :test 'equal)))
    (loop for (key value) on keys-and-values by #'cddr
          do (setf (gethash key table) value))
    table))
TABLE

(defparameter *heroes*
  (table "Avengers"
         (table "Retired" (table "Tony Stark" "Iron Man")
                "Active" (table "Bruce Banner" "Hulk"))))
Run Code Online (Sandbox Code Playgroud)

通常,我们使用access:access一致的方式访问各种数据结构(alist,plist,哈希表,对象等)。对于嵌套访问,我们使用access:accesses(复数):

(access:accesses *heroes* "Avengers" "Retired" "Tony Stark")
"Iron Man"
Run Code Online (Sandbox Code Playgroud)

此外,我们可以setf做到:

(setf (access:accesses *heroes* "Avengers" "Retired" "Tony Stark") "me")
"me"
Run Code Online (Sandbox Code Playgroud)

它是经过战斗验证的库,因为它是Djula模板库(下载次数最多的Quicklisp库)之一的核心。

我的博客文章:https : //lisp-journey.gitlab.io/blog/generice-consistent-access-of-data-structures-dotted-path/