如何解决有没有办法只使用应用程序编程并避免递归或迭代作为编程风格在 Common Lisp 中实现 mapcar?
我正在尝试通过Common Lisp:符号计算的温和介绍这本书来学习 Common Lisp。此外,我正在使用 SBCL、Emacs 和 Slime。
在第 7 章中,作者建议本书将涵盖三种编程风格:递归、迭代和应用程序编程。
我对最后一个感兴趣。这种风格以 applicative operator funcall
而闻名,它是负责其他 applicative 运算符(如 mapcar
)的原语。
因此,出于教育目的,我决定使用 mapcar
实现我自己的 funcall
版本:
(defun my-mapcar (fn xs)
(if (null xs)
nil
(cons (funcall fn (car xs))
(my-mapcar fn (cdr xs)))))
如您所见,我使用递归作为一种编程风格来构建标志性的应用程序编程函数。
它似乎有效:
CL-USER> (my-mapcar (lambda (n) (+ n 1)) (list 1 2 3 4))
(2 3 4 5)
CL-USER> (my-mapcar (lambda (n) (+ n 1)) (list ))
NIL
;; comparing the results with the official one
CL-USER> (mapcar (lambda (n) (+ n 1)) (list ))
NIL
CL-USER> (mapcar (lambda (n) (+ n 1)) (list 1 2 3 4))
(2 3 4 5)
有没有办法在不使用递归或迭代的情况下实现 mapcar?仅使用应用性编程作为一种风格?
谢谢。
Obs.:我试着看看它是如何实现的。但这是不可能的
CL-USER> (function-lambda-expression #'mapcar)
NIL
T
MAPCAR
我还使用 Emacs M-.
来查找文档。但是,以下几点对我没有帮助。我使用 this 找到以下文件:
/usr/share/sbcl-source/src/code/list.lisp
(DEFUN MAPCAR)
/usr/share/sbcl-source/src/compiler/seqtran.lisp
(:DEFINE-SOURCE-TRANSFORM MAPCAR)
/usr/share/sbcl-source/src/compiler/fndb.lisp
(DECLaim MAPCAR SB-C:DEFKNowN)
解决方法
coxme(latency ~ tests + (1|ID),data = df)
Error in if (n == 0) stop("No observations remain in the data set") :
argument is of length zero
本身是一个原始的应用运算符(Common Lisp 的第 220 页:符号计算的温和介绍)。所以,如果你想以一种应用的方式重写它,你应该使用其他一些原始的应用运算符,例如 map
或 map-into
。例如,使用 df <- data.frame(ID = rep(c(LETTERS[1:20]),each=4),tests = rep(letters[1:4],replace = FALSE),time = abs(rnorm(80,mean = 10,sd = 4)),latency = ifelse(time > 20,20,time))
:
mapcar
,
实现 mapcar
的另一种方法是使用更通用的 reduce
函数(也称为折叠)。让我们将用户提供的函数命名为 f
并定义 my-mapcar
。
reduce
函数携带一个累加器值,用于构建结果列表,这里它将采用值 v
、子列表 rest
,并调用 cons
(funcall f v)
和 rest
,以构建列表。
更准确地说,这里 reduce
将实现右折叠,因为 cons
是右结合的(例如递归列表是“右侧”,即cons
,例如 (cons a (cons b (cons nil)))
)。
为了用reduce
定义一个右折叠,你传递:from-end t
,这表示它从最后一个元素和初始累加器建立一个值来获得一个新的累加器值,然后使用该新累加器的倒数第二个元素来构建新的累加器,等等。这是确保结果元素与输入列表的顺序相同的方法。
在这种情况下,reduce 函数将当前元素作为第一个参数,将累加器作为第二个参数。
由于元素的类型和累加器的类型不同,你需要为累加器传递一个:initial-value
(从列表中获取初始值的默认行为是像{ {1}} 或 +
,其中累加器与列表元素在同一域中)。
考虑到这一点,你可以这样写:
*
例如:
(defun my-map (f list)
(reduce (lambda (v rest) (cons (funcall f v) rest))
list
:from-end t
:initial-value nil))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。