LISP:为什么mapcan 不接受我的列表作为参数?

2024-01-12

为了简化我的问题: 为什么这有效

(mapcan #'(lambda (l) (list '1 '2) ) '(a b))

这并不

(mapcan #'(lambda (l) '(1 2) ) '(a b))

?

我必须编写一个函数,使用映射函数在给定列表 L 的所有级别上替换列表 D 的所有元素中的一个元素。 我尝试使用mapcan为了这:

(defun subAll (l k d)
  (cond 
    ((and (atom l) (eq l k)) 
     d)
    ((and (atom l) (not (eq l k)))
     (cons l '()))
    (t (cons 
         (mapcan #'(lambda (l) (subAll l k d)) l)
         '()))))

但我得到这两个输入的以下结果:

1.

(subAll '(1(2(3(4(5(6(7)))))) (2(3(4 7(4(4(4(4)))))))) '7 '(a b))
 => ((1(2(3(4(5(6(A B(4(4(4(4)))))))))) (2(3(4 A B(4(4(4(4)))))))))

2.

(subAll '(1 2 3 (4 2 (3 2 (2)))) '2 '(99 98))
=>Lisp stack overflow.

但如果更换((and (atom l) (eq l k)) d) with ((and (atom l) (eq l k)) (list 'a 'b))它适用于输入 1。此外,我还制作了自己的函数,仅解构列表并重建它:

(defun lst(l)
(cond
    ((null l) nil)
    (t (cons (car l) ( lst (cdr l))))))

如果更换它就可以工作((and (atom l) (eq l k)) d) with ((and (atom l) (eq l k)) (lst d))对于我上面的两个输入。

  1. => ((1(2(3(4(5(6(A B)))))) (2(3(4 A B(4(4(4(4)))))))))

  2. => ((1 A B 3 (4 A B (3 A B (A B)))))

mapcan 是否只接受特殊类型的列表?如果有人可以向我解释为什么会这样做或提供其他解决方案,我将不胜感激。 (我不能使用任何内置函数,如列表或附加,只有当我制作自己的附加和列表时)

我正在使用 GNU CLISP 2.49


简短回答:

mapcan具有破坏性。

根据超规格条目开启quote http://www.lispworks.com/documentation/HyperSpec/Body/s_quote.htm,

“后果是不明确的 https://en.wikipedia.org/wiki/Undefined_behavior如果文字对象(包括引用的对象)被破坏性修改。”

解决此问题的最简单方法是不使用mapcan.

(defun subAll (l k d)
  (cond 
    ((and (atom l) (eq l k)) 
     d)
    ((and (atom l) (not (eq l k)))
     (cons l '()))
    (t (cons 
         (loop for elem in l append (subAll elem k d))
         '()))))

有了这个定义,

CL-USER> (suball '(1 2 3 (4 2 (3 2 (2)))) '2 '(99 98))
((1 99 98 3 (4 99 98 (3 99 98 (99 98)))))
CL-USER> 

长答案:

让我先解决一些风格问题。


Please 正确格式化您的代码 http://dept-info.labri.fr/~idurand/enseignement/lst-info/PFS/Common/Strandh-Tutorial/indentation.html。它会让您和试图帮助您的人更容易阅读。

(defun subAll (l k d)
  (cond 
    ((and (atom l) (eq l k)) 
     d)
    ((and (atom l) (not (eq l k)))
     (cons l '()))
    (t (cons 
         (mapcan #'(lambda (l) (subAll l k d)) l)
         '()))))

接下来,Common Lisp 的标准命名风格是train-case. Also, (cons foo '()), (cons foo nil) and (list foo)都是等价的。您也可以使用最短的。 (你也不need尖锐引用lambda形式,尽管它并没有特别伤害)。

(defun sub-all (l k d)
  (cond 
    ((and (atom l) (eq l k)) 
     d)
    ((atom l)
     (list l))
    (t (list (mapcan #'(lambda (l) (sub-all l k d)) l)))))

让我们看一下您的函数在此期间运行时发生了什么stack overflow case.

; SLIME 2013-04-02
CL-USER> (defun sub-all (l k d)
  (cond 
    ((and (atom l) (eq l k)) 
     d)
    ((atom l)
     (list l))
    (t (list (mapcan #'(lambda (l) (sub-all l k d)) l)))))
;Compiler warnings :
;   In an anonymous lambda form inside SUB-ALL: Undefined function SUB-ALL
SUB-ALL
CL-USER> (trace sub-all)
NIL
CL-USER> (sub-all '(1 2 3 (4 2 (3 2 (2)))) '2 '(99 98))
0> Calling (SUB-ALL (1 2 3 (4 2 (3 2 (2)))) 2 (99 98)) 
 1> Calling (SUB-ALL 1 2 (99 98)) 
 <1 SUB-ALL returned (1)
 1> Calling (SUB-ALL 2 2 (99 98)) 
 <1 SUB-ALL returned (99 98)
 1> Calling (SUB-ALL 3 2 (99 98)) 
 <1 SUB-ALL returned (3)
 1> Calling (SUB-ALL (4 2 (3 2 (2))) 2 (99 98 3)) 
  2> Calling (SUB-ALL 4 2 (99 98 3)) 
  <2 SUB-ALL returned (4)
  2> Calling (SUB-ALL 2 2 (99 98 3)) 
  <2 SUB-ALL returned (99 98 3)
  2> Calling (SUB-ALL (3 2 (2)) 2 (99 98 3)) 
   3> Calling (SUB-ALL 3 2 (99 98 3)) 
   <3 SUB-ALL returned (3)
   3> Calling (SUB-ALL 2 2 (99 98 3)) 
   <3 SUB-ALL returned (99 98 3)
   3> Calling (SUB-ALL (2) 2 (99 98 3)) 
    4> Calling (SUB-ALL 2 2 (99 98 3)) 
    <4 SUB-ALL returned (99 98 3)
   <3 SUB-ALL returned ((99 98 3))
  <2 SUB-ALL returned ((3 99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 ...

您实际上永远不会看到关键突变点,但您可以看到早期的等效点(请注意,通过调用的第二“层”,d is (99 98 3),而不是(99 98)您最初传入的)。在那之后不久的某个时刻,d变成(99 98 3 (2)),此时循环将无限进行,因为您可以在替换对象内找到目标。当我需要时我通常会做什么mapcan正在定义我自己的功能版本。

(defun mappend (fn list)
  (loop for elem in list
     append (funcall fn elem)))

(defun sub-all (tree target replacement)
  (cond 
    ((and (atom tree) (eq tree target)) 
     replacement)
    ((atom tree)
     (list tree))
    (t (list 
         (mappend 
           (lambda (sub) 
             (sub-all sub target replacement))
           tree)))))

这也解决了引用列表的未定义行为。具体来说,根据上面的定义mappend,

CL-USER> (mappend #'(lambda (l) '(1 2)) '(a b))
; in: MAPPEND #'(LAMBDA (L) '(1 2))
;     #'(LAMBDA (L) '(1 2))
; 
; caught STYLE-WARNING:
;   The variable L is defined but never used.
; 
; compilation unit finished
;   caught 1 STYLE-WARNING condition
(1 2 1 2)
CL-USER> (mappend #'(lambda (l) (declare (ignore l)) '(1 2)) '(a b))
(1 2 1 2)
CL-USER> 

查看这个答案 https://stackoverflow.com/a/18790523/190887(上面已由 Joshua Taylor 链接)了解更多详细信息。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LISP:为什么mapcan 不接受我的列表作为参数? 的相关文章

  • 列表子类的 Python 类型

    我希望能够定义列表子类的内容必须是什么 该类如下所示 class A list def init self list init self 我想包括打字 这样就会发生以下情况 import typing class A list typing
  • 在 Python 中获取数组作为 GET 查询参数

    我知道在 php 中我可以使用 GET key1 key2 检索以数组形式发送的 GET 数据 但这在 Python 中是可能的 因为我只收到一个字符串 但它不被识别为数组 列表 如果重要的话我使用flask werkzeug 参数名称的深
  • 在Python中将字符串转换为字典或列表?

    在Python中将此字符串转换为列表或字典 u f i r s t n a m e u j o h n u l a s t n a m e u s m i t h u a g e 2 0 u m o b
  • C++ std::list:迭代时擦除/删除元素[重复]

    这个问题在这里已经有答案了 可能的重复 您可以在迭代 std list 时从其中删除元素吗 https stackoverflow com questions 596162 can you remove elements from a st
  • 一次性的 lisp 宏,我的实现正确吗?

    我正在尝试从 Peter Seibel 的书 Practical Common Lisp 中学习 Lisp 在第 8 章 宏 定义你自己的 http www gigamonkeys com book macros defining your
  • 列表值意外变化[重复]

    这个问题在这里已经有答案了 为什么是这个列表r即使我只是想更改列表 也会被更改v 即使它们不指向相同的内存位置 r v list r 2 2 1 2 8 3 10 2 1 8 4 2 4 6 4 for c a in enumerate r
  • Python 中两个列表列表的高效比较

    我是 python 的新手 只是在做项目时学习一些东西 这里我有两个列表列表 我需要比较和分离 A gt B 中找到的差异和 b gt A 中找到的差异 最好的比较方法是什么 A 1L test case 1 1L test case 2
  • 计算例如具有多列 data.frames 的列表中的平均值

    我有几个 data frames 的列表 每个 data frame 有几列 通过使用mean mylist first dataframe a我可以得到这个 data frame 中 a 的平均值 但是我不知道如何计算列表中存储的所有 d
  • 如何在 Python 中使用 .format() 打印“for”循环中的列表?

    我是 Python 新手 我正在编写一段非常简单的代码 使用 for 循环打印列表的内容 format 我想要如下的输出 但我收到此错误 names David Peter Michael John Bob for i in names p
  • 如何在 Visual Studio Code 上运行 Scheme?

    我想知道如何在 Visual Studio Code 上运行简单的方案代码 我已经安装了一个名为 Scheme 的扩展 但下一步是什么 我没有找到有关如何运行代码或开发人员联系方式的扩展的任何详细信息 现在在 VSCode 上编译Schem
  • 关于执行令的问题

    我正在尝试学习 Common Lisp 并在 repl 中尝试某些东西时发现了一些意想不到的东西 对我来说 基于大多数编程语言的执行顺序 以及我一直从 lisp 听到的出色的一流函数支持 我认为以下应该可行 if t format t te
  • 如何在 NHibernate 命名查询参数上设置 C# 可为空值类型值?

    我正在使用 NHibernate 并通过命名查询调用存储过程
  • 如何在 C 中调用采用匿名结构的函数?

    如何在 C 中调用采用匿名结构的函数 比如这个函数 void func struct int x p printf i n p x 当提供原型的函数声明在范围内时 调用该函数的参数必须具有与原型中声明的类型兼容的类型 其中 兼容 具有标准定
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 颤动:所选值不显示在下拉列表中

    我正在从 SQLite 数据库填充城市名称并尝试显示为下拉列表 我通过遵循教程使其工作 但遇到了一个小问题 所选值不会显示在下拉列表中 它继续显示默认提示值 但是 我能够分配和检索正确的选定值 这是我的代码 cities dart clas
  • xgboost :base_score参数的含义

    在 xgboost 的文档中我读到 基本分数 default 0 5 所有的初始预测分数 实例 全局偏差 这句话的意思是什么 基本分数是数据集中感兴趣事件的先验概率吗 IE 在包含 1 000 个观察值 其中 300 个正值和 700 个负
  • 查找嵌套列表中元素的索引?

    我有一个类似的列表 mylist lt list a 1 b list A 1 B 2 c list C 1 D 3 是否有一种 无循环 方法来识别元素的位置 例如如果我想用 5 替换 C 的值 并且在哪里找到元素 C 并不重要 我可以这样
  • 如何将列表列表写入 CSV 文件 Python?

    我有一个列表 例如 a b c d e f 我想将其写入 CSV 文件 如下所示 a b c d e f 我怎么做 我尝试过使用 csv writerows 但输出文件的每个字符位于不同的单元格中 并且全部位于同一行中 从某种意义上说 第一
  • 有没有一种简单的方法来判断存储在一个列表中的许多数据帧是否包含相同的列?

    我有一个包含许多数据框的列表 df1 lt data frame A 1 5 B 2 6 C LETTERS 1 5 df2 lt data frame A 1 5 B 2 6 C LETTERS 1 5 df3 lt data frame
  • R - 通过覆盖和递归合并列表

    假设我有两个带有名字的列表 a list a 1 b 2 c list d 1 e 2 d list a 1 b 2 b list a 2 c list e 1 f 2 d 3 e 2 我想递归地合并这些列表 如果第二个参数包含冲突的值 则

随机推荐