在common-lisp中更好的pythonic`join`

时间:2018-06-01 16:27:48

标签: lisp common-lisp metaprogramming

在Edi Weitz的cl cookbook中,对于pythonic join,建议使用此函数:

(defun join (separator list)
  (with-output-to-string (out)
    (loop for (element . more) on list
          do (princ element out)
          when more
            do (princ separator out))))

然而,不知何故,我在思考,必须有一种方式以另一种方式表达join,可能使用format的能力......

在Seibel的书中,(在关于format的章节中)我们发现列表中的字符串连接到带有分隔符的单个字符串 ", "

(defvar l '("a" "b" "c"))

(format nil "~{~A~^, ~}" l)
;; "a, b, c"

这是一个pythonic连接,非常简洁; ~^指令使", "仅添加到最后一个元素之前,并且在没有元素跟随时添加。{/ p>

但是,这里,分隔符字符串", "是format指令的一部分。

一个棘手的案例是(defvar sep #\Tab)。 如果sep "#\Tab"的表示字面上可以作为这个格式指令中间的分隔符放置,导致:

(format nil "~{~A~^#\Tab~}" l)

我们会达到目标。

显然,必须使用宏来生成格式指令... 我尝试了(princ-to-string sep)之类的内容,但这会提供"#\\Tab"而非"#\Tab"

E.g。

(defmacro join (sep l)
  `(format nil ,(format nil "~{~A~}" `("\~\{\~A\~\^" ,(write-to-string sep) "\~\}")) l))

但是在尝试时:

(join #\Tab '("a" "b" "c"))

这个结果当然是不可取的:"a#\\Tabb#\\Tabc",因为

(macroexpand-1 '(join #\Tab '("a" "b" "c")))
;; results in:
(FORMAT NIL "~{~A~^#\\Tab~}" L)
;; instead of:
(FORMAT NIL "~{~A~^#\Tab~}" L)

但是我没有看到如何实现这个步骤到所需的宏... 有没有人对此有所启发?

关于元编程问题的一种元编程......

好的,现在我知道,@ Rainer Joswig已经发布了 What's the canonical way to join strings in a list?

解决这个问题。但是,如果有一种方法,将"#\\Tab"表示为"#\Tab",可以得出一个更紧凑的定义。 但不知何故,Lisp读者似乎总是将"\Tab"识别为一个字母。是否有可能编写一个函数来做到这一点?

备注

在R中,特别存在元编程,像as.name("myvar")这样的函数,它们从字符串“myvar”中生成符号myvar。 和deparse(substitute(x))之类的表达式,它采用符号x并从中创建一个文字字符串"x"。 Deparse退回执行print()命令,从而转义特殊符号。例如deparse(deparse(substitute(x)))生成"\"x\"" - 围绕此表达式parse(text = ... )"x"再次parse(text = deparse(deparse(substitute(x)))) (a-special-function #\Tab)。 如何在普通的lisp中获得这样的东西? 例如。"#\Tab"导致(字面):sudo mkdir /mnt/7282B48E0BE626E0 作为字符串?

后记

谢谢@Sylwester !!他没有宏就解决了。非常优雅!

1 个答案:

答案 0 :(得分:6)

您的问题是您尝试将module.exports = { getAssetExts() { return ['mp3', 'mp4'] } } 添加到格式中,但这就是您使用文字的方式。如果您只是在格式字符串中插入制表符或由其组成的字符串,它将执行您想要的操作:

#\Tab