执行一个函数,直到返回nil,将其值收集到一个列表中 [英] Executes a function until it returns a nil, collecting its values into a list
问题描述
我从 XKCD的Hofstadter漫画中得到了这个主意;在(任何)Lisp方言中创建条件循环的最佳方法是什么,该条件循环执行一个函数,直到返回NIL
,这时它将返回的值收集到列表中.
I got this idea from XKCD's Hofstadter comic; what's the best way to create a conditional loop in (any) Lisp dialect that executes a function until it returns NIL
at which time it collects the returned values into a list.
对于那些没有看过这个笑话的人,道格拉斯·霍夫施塔特的八字"自传由六个词组成:我很元,甚至这个缩写"都包含笑话的延续:(有些奇怪meta-paraprosdokian?)是Meta"吗?开个玩笑就是自传实际上是我是如此的Meta,即使这个首字母缩写是Meta".但是为什么不更深入呢?
For those who haven't seen the joke, it's goes that Douglas Hofstadter's "eight-word" autobiography consists of only six words: "I'm So Meta, Even This Acronym" containing continuation of the joke: (some odd meta-paraprosdokian?) "Is Meta" — the joke being that the autobiography is actually "I'm So Meta, Even This Acronym Is Meta". But why not go deeper?
假定首字母缩略词功能META
从字符串中创建首字母缩写词并将其拆分为单词,如果字符串中仅包含一个单词,则返回NIL
:
Assume the acronymizing function META
that creates an acronym from a string and splits it into words, returns NIL
if the string contains but one word:
(meta "I'm So Meta, Even This Acronym") ⇒ "Is Meta"
(meta (meta "I'm So Meta, Even This Acronym")) ⇒ "Im"
(meta (meta (meta "I'm So Meta, Even This Acronym"))) ⇒ NIL
(meta "GNU is Not UNIX") ⇒ "GNU"
(meta (meta "GNU is Not UNIX")) ⇒ NIL
现在我正在寻找如何实现函数,以便:
Now I'm looking for how to implement a function so that:
(so-function #'meta "I'm So Meta, Even This Acronym")
⇒ ("I'm So Meta, Even This Acronym" "Is Meta" "Im")
(so-function #'meta "GNU is Not Unix")
⇒ ("GNU is Not Unix" "GNU")
做到这一点的最好方法是什么?
What's the best way of doing this?
推荐答案
这很容易.我不想写一个解决方案,所以我会写-但是它将是笨拙的elisp版本,如果您遵循以下步骤,可能会导致意想不到的启发:
This is easy. I don't want to write a solution, so instead I will -- but it'll be the crappy elisp version, which might lead to unexpected enlightenment if you'll follow through:
(defun so-function (f str)
(let (x '())
(while str (setq x (cons str x)) (setq str (funcall f str)))
(reverse x)))
要尝试此操作,您将需要meta
,但我不知道您如何决定将空格放置在何处,因此我会伪造它:
To try this out you'll need that meta
, but I don't know how you'd decide where to put the spaces, so instead I'll fake it:
(defun meta (x)
(cadr (assoc x '(("I'm So Meta, Even This Acronym" "Is Meta")
("Is Meta" "Im")
("GNU is Not UNIX" "GNU")))))
这使您想要的代码起作用.至于启蒙-尝试编写它而不是您想要的东西,so-function
将是一个高阶函数-它将像这样工作:
This makes the code that you want work. As for the enlightenment -- try to write it so instead of what you want, so-function
will be a higher order function -- one that will work like this:
(funcall (so-function #'meta) "GNU is Not UNIX")
或者,在Scheme中:
or, in Scheme:
((so-function meta) "GNU is Not UNIX")
这里最大的提示是您不能用简单的elisp做到(至少不是没有cl
库的技巧).为了获得充分的信誉,请避免出现突变-这将导致您以自然的方式在Scheme中编写它,甚至看起来比setq
版本更具可读性.
The big hint here is that you can't do it in plain elisp (at least not without tricks from the cl
library). To get full credit, avoid the mutations -- this will lead to the natural way you'd write it in Scheme, and might even look more readable than the setq
version.
这篇关于执行一个函数,直到返回nil,将其值收集到一个列表中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!