Lisp字符串格式化与命名参数

12
有没有一种在Lisp中使用命名参数格式化字符串的方法?
也许可以使用关联列表之类的东西。
(format t "All for ~(who)a and ~(who)a for all!~%" ((who . "one")))

为了打印出"All for one and one for all",类似于this python questionthis scala one或者甚至是c++,但是在Lisp中。
如果这个功能不在语言中,是否有任何酷炫的函数或宏可以实现相同的效果?

1
FYI,在CL21中可以使用#"读取器宏实现。https://lispcookbook.github.io/cl-cookbook/cl21.html#string-interpolation - Ehvince
1个回答

18
使用CL-INTERPOL
(cl-interpol:enable-interpol-syntax)

字符串插值

对于简单的情况,你不需要使用 FORMAT

(lambda (who) #?"All for $(who) and $(who) for all!")

然后:

(funcall * "one")
=> "All for one and one for all!"

解释格式指令

如果需要进行格式化,可以使用以下方法:

(setf cl-interpol:*interpolate-format-directives* t)

例如,这个表达式:
(let ((who "one"))
  (princ #?"All for ~A(who) and ~S(who) for all!~%"))

...打印:

All for one and "one" for all!

如果你好奇,上面的内容可以这样理解:
(LET ((WHO "one"))
  (PRINC
    (WITH-OUTPUT-TO-STRING (#:G1177)
      (WRITE-STRING "All for " #:G1177)
      (FORMAT #:G1177 "~A" (PROGN WHO))
      (WRITE-STRING " and " #:G1177)
      (FORMAT #:G1177 "~S" (PROGN WHO))
      (WRITE-STRING " for all!" #:G1177))))

替代读取器函数

以前,我全局设置了*interpolate-format-directives*,它会解释所有插值字符串中的格式指令。 如果您想精确控制何时插入格式指令,您不能仅在代码中临时绑定变量,因为这种魔法发生在读取时。相反,您必须使用自定义读取器函数。

(set-dispatch-macro-character
 #\#
 #\F
 (lambda (&rest args)
   (let ((cl-interpol:*interpolate-format-directives* t))
     (apply #'cl-interpol:interpol-reader args))))

如果我将特殊变量重置为其默认值NIL,则格式化指令的字符串前缀为#F,而正常插值使用#?语法。如果您想更改读取表,请查看命名读取表


2
我不使用它,但我听说CL Interpol正在寻找我。 - Kaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接