在 common lisp 中编写一个返回列表的否定的函数

发布于 2024-10-07 14:36:25 字数 724 浏览 0 评论 0原文

我的当前代码出现此错误:

 LET: illegal variable specification
   (COND (LISTP A (IF (NEGATE A) (NEGATE (REST L)) NIL))
    (T (SETF A (-A) (APPEND (LIST A) (REST L)) (NEGATE (REST L)) NIL)))

我当前的代码:

(defun negate(L)
 (setq x -1)

 (if (not (null L))

  (let ((a (fitst L))
        (cond (listp a
              (if (negate a)
                  (negate (rest L))
                nil))
        (t
         (setf a (-a) (append (list a)(rest L))
               (negate (rest L))
               nil))))
)
))

以及它需要通过的测试用例

o List is  (1 2 3 4)  
o Output should be: (-1 -2 -3 -4)

o List is  (1 -2 (3 4))  
o Output should be: (-1 2 (-3 -4) )

I get this error with my current code:

 LET: illegal variable specification
   (COND (LISTP A (IF (NEGATE A) (NEGATE (REST L)) NIL))
    (T (SETF A (-A) (APPEND (LIST A) (REST L)) (NEGATE (REST L)) NIL)))

my current code:

(defun negate(L)
 (setq x -1)

 (if (not (null L))

  (let ((a (fitst L))
        (cond (listp a
              (if (negate a)
                  (negate (rest L))
                nil))
        (t
         (setf a (-a) (append (list a)(rest L))
               (negate (rest L))
               nil))))
)
))

and the test cases it needs to pass

o List is  (1 2 3 4)  
o Output should be: (-1 -2 -3 -4)

o List is  (1 -2 (3 4))  
o Output should be: (-1 2 (-3 -4) )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

抠脚大汉 2024-10-14 14:36:25

从最礼貌的意义上来说,你的代码有点不对劲。这周你正在学习 Lisp,不是吗?没关系!这是一门有趣的语言,确实可以做一些很棒的事情。

因此,我将逐步介绍例程的创建过程,并带您参观。

您的基本情况是 -

(defun negate (n) 
  (if (> n 0) (- 0 n)))

(map #'negate '(1 2 3 4))

遍历树更复杂,但让我们来看看这些想法。

本质上,您需要回答三种情况:当前元素是 nil、列表还是原子?

(if (not (car seq)) 
  (if (listp (car seq))
    ;;Recurse
    ;;Otherwise negate the current element and append it to the recursed.

让我们尝试一下这个:

(defun negate-seq (seq)
  (if (not seq)
      (return-from negate-seq))

  (if (listp (car seq))
      (negate-seq seq)
    (list (negate (car seq)) (negate-seq (cdr seq)))))

太棒了!
除了...

(negate-seq '(1 2)) ==> (-1 (-2 NIL))

还有...

 (negate-seq '(1 (1 2 -3))) ==> STACK OVERFLOW!

哦天哪。我们现在有麻烦了。

首先,我们尝试使用 cons 而不是 list
这解决了奇怪的嵌套列表问题。

很明显,我们陷入了无限递归的循环。这应该是不可能的,因为我们有 not seq 保护。好吧,让我们尝试一下调试。我正在使用 CLISP,我可以通过以下方式跟踪参数:

(trace 'negate-seq) 

然后,

(negate-seq '(1 (1 2 -3)))

突然我看到 Crikey 的爆炸

1621. Trace: (NEGATE-SEQ '((1 2 -3)))
1622. Trace: (NEGATE-SEQ '((1 2 -3)))
1623. Trace: (NEGATE-SEQ '((1 2 -3)))
1624. Trace: (NEGATE-SEQ '((1 2 -3)))

,我忘记了我的 cdr 和 cons up 列表案例!嗯嗯。

让我们试试这个:

(defun negate-seq (seq)
  (if (not seq)
      (return-from negate-seq))

  (if (listp (car seq))
      (cons (negate-seq (car seq))
        (negate-seq (cdr seq)))
    (cons (negate (car seq)) (negate-seq (cdr seq)))))

对汽车进行递归,对汽车进行回避,将它们放在一起,我们可能会有所发现。

 (negate-seq '(1 (1 2 -3))) =>  (-1 (-1 -2 NIL)

嗯嗯。让我们看一下踪迹。

  1. 跟踪:(NEGATE-SEQ '(1 (1 2 -3)))
  2. 跟踪:(NEGATE-SEQ '((1 2 -3)))
  3. 跟踪:(NEGATE-SEQ '(1 2 -3))
  4. 跟踪:(NEGATE-SEQ '(2 -3))
  5. 跟踪:(NEGATE-SEQ '(-3))
  6. 跟踪:(NEGATE-SEQ 'NIL)
  7. 跟踪:NEGATE-SEQ ==>无
  8. 跟踪:NEGATE-SEQ ==> (无)
  9. 跟踪:NEGATE-SEQ ==> (-2 无)
  10. 跟踪:NEGATE-SEQ ==> (-1 -2 无)
  11. 跟踪:(NEGATE-SEQ 'NIL)
  12. 跟踪:NEGATE-SEQ ==>无
  13. 跟踪:NEGATE-SEQ ==> ((-1 -2 无))
  14. 跟踪:NEGATE-SEQ ==> (-1 (-1 -2 无))

所以我递归直到-3,然后....它脱落了?奇怪的。啊!我不断地抓取事物的 CDR。 CDR 始终是一个列表。 (cdr '(-3)) 为零!

让我们看看这里......

(翻来覆去)

负数在正数上返回零。噢。

(defun negate (n) 
  (if ( > n 0) 
      (- 0 n)
    n))


(defun negate-seq (seq)
  "Written by Paul Nathan"
  (if (not seq)
      (return-from negate-seq))

  (if (listp (car seq))
      (cons (negate-seq (car seq))
        (negate-seq (cdr seq)))
    (cons (negate (car seq)) 
      (negate-seq (cdr seq)))))

In the most polite sense, your code is a bit off. You're learning Lisp this week, aren't you? That's OK! It's a fun language and can really do some awesome things.

So I'm going to walk through the creation of the routine, and take you along the tour.

Your basic case is -

(defun negate (n) 
  (if (> n 0) (- 0 n)))

(map #'negate '(1 2 3 4))

Walking the tree is more complex, but let's walk through the ideas.

Essentially, you have three cases to answer: is the current element nil, a list or an atom?

(if (not (car seq)) 
  (if (listp (car seq))
    ;;Recurse
    ;;Otherwise negate the current element and append it to the recursed.

Let's try a first cut at this:

(defun negate-seq (seq)
  (if (not seq)
      (return-from negate-seq))

  (if (listp (car seq))
      (negate-seq seq)
    (list (negate (car seq)) (negate-seq (cdr seq)))))

That's great!
Except...

(negate-seq '(1 2)) ==> (-1 (-2 NIL))

And...

 (negate-seq '(1 (1 2 -3))) ==> STACK OVERFLOW!

Oh boy. We're in trouble now.

First, let's just try a cons instead of a list.
That cleans up the weird nested list problem.

It's obvious that we're gotten into a loop of infinite recursion. That shouldn't be possible, because we've got the not seq guard. Okay, so let's try an debug. I'm using CLISP, and I can trace arguments with:

(trace 'negate-seq) 

then,

(negate-seq '(1 (1 2 -3)))

Suddenly I see an explosion of

1621. Trace: (NEGATE-SEQ '((1 2 -3)))
1622. Trace: (NEGATE-SEQ '((1 2 -3)))
1623. Trace: (NEGATE-SEQ '((1 2 -3)))
1624. Trace: (NEGATE-SEQ '((1 2 -3)))

Crikey, I forgot my cdr and to cons up the list case! Hmmmm.

Let's try this:

(defun negate-seq (seq)
  (if (not seq)
      (return-from negate-seq))

  (if (listp (car seq))
      (cons (negate-seq (car seq))
        (negate-seq (cdr seq)))
    (cons (negate (car seq)) (negate-seq (cdr seq)))))

Recurse for the car, recuse on the car, cons them together, we might be on to something.

 (negate-seq '(1 (1 2 -3))) =>  (-1 (-1 -2 NIL)

Hmmmm. Let's take a look at the trace.

  1. Trace: (NEGATE-SEQ '(1 (1 2 -3)))
  2. Trace: (NEGATE-SEQ '((1 2 -3)))
  3. Trace: (NEGATE-SEQ '(1 2 -3))
  4. Trace: (NEGATE-SEQ '(2 -3))
  5. Trace: (NEGATE-SEQ '(-3))
  6. Trace: (NEGATE-SEQ 'NIL)
  7. Trace: NEGATE-SEQ ==> NIL
  8. Trace: NEGATE-SEQ ==> (NIL)
  9. Trace: NEGATE-SEQ ==> (-2 NIL)
  10. Trace: NEGATE-SEQ ==> (-1 -2 NIL)
  11. Trace: (NEGATE-SEQ 'NIL)
  12. Trace: NEGATE-SEQ ==> NIL
  13. Trace: NEGATE-SEQ ==> ((-1 -2 NIL))
  14. Trace: NEGATE-SEQ ==> (-1 (-1 -2 NIL))

So I recurse until the -3, then.... it falls off? Odd. Ah! I'm continually grabbing the CDR of things. A CDR is always a list. (cdr '(-3)) is nil!

Let's see here....

(much rummaging around)

Negate returns nil on positive. D'oh.

(defun negate (n) 
  (if ( > n 0) 
      (- 0 n)
    n))


(defun negate-seq (seq)
  "Written by Paul Nathan"
  (if (not seq)
      (return-from negate-seq))

  (if (listp (car seq))
      (cons (negate-seq (car seq))
        (negate-seq (cdr seq)))
    (cons (negate (car seq)) 
      (negate-seq (cdr seq)))))
ゞ记忆︶ㄣ 2024-10-14 14:36:25

我不确定您是否正在寻找一种温和的推动来纠正所提供的代码,或者您是否正在寻求其他方法来做到这一点。我的第一个想法是 mapcar

(defun negate-tree (tree)
  (mapcar (lambda (e)
            (cond 
              ((null e) nil)
              ((listp e) (negate-tree e))
              (t (- e))))
          tree))

然后您可以概括否定方面,并编写 map-tree 来代替,接受一个应用于树中原子的函数:

(defun map-tree (f tree)
  (mapcar (lambda (e)
            (cond 
              ((null e) nil)
              ((listp e) (map-tree f e))
              (t (funcall f e))))
          tree))

您可以使用一元否定函数来调用它:

(map-tree #'- '(1 -2 (3 4)))

这样的调用假设树中的所有叶子都被一元否定函数容纳nil

接受 nil 作为树中可能的叶子会使访问算法有点混乱,并且不清楚提供的函数 f 是否应该应用于所有叶子 - 即使是那些都是nil——这样函数本身就可以决定是否以及如何处理nil

此版本的另一个缺陷是它如何处理非 的缺点单元正确的列表。请注意,函数 listp 对所有返回 true cons 单元格——即使那些不构成正确列表的单元格——但 mapcar 确实要求其输入是正确列表。我们可以沿着“listp true”路径,递归调用mapcar,并让mapcar因接收到不正确的列表而失败。这意味着上面的算法需要测试 cons 单元格,看看它们是否是正确的列表,然后再将它们交给 mapcar,也许将那些不是叶子的单元格(我不愿意说)此处的“原子”),或者记录预期的树结构由正确列表的正确列表组成。

如果您需要接受不一定列出自身的顶级“树”,这意味着一个单独的原子是一个有效的树,或者 nil 是一个有效的树,您可以拆开以下的组成部分上面的函数,并在确定所检查的树是一个列表后编写一个仅使用 mapcar 的函数。

I'm not sure if you were looking for a gentle nudge to correct the code presented, or if you're soliciting other ways to do it. My first thought went to mapcar:

(defun negate-tree (tree)
  (mapcar (lambda (e)
            (cond 
              ((null e) nil)
              ((listp e) (negate-tree e))
              (t (- e))))
          tree))

You can then generalize out the negation aspect, and write map-tree instead, accepting a function to apply to the atoms in the tree:

(defun map-tree (f tree)
  (mapcar (lambda (e)
            (cond 
              ((null e) nil)
              ((listp e) (map-tree f e))
              (t (funcall f e))))
          tree))

You can call on it with, say, the unary negation function:

(map-tree #'- '(1 -2 (3 4)))

Such a call assumes that all the leaves in the tree are either nil accommodated by the unary negation function.

Accepting nil as a possible leaf in the tree makes the visitation algorithm a little messy, and it's not clear whether the provided function f should be applied to all leaves—even those that are nil—so that the function itself can decide whether and how to treat nil.

Another deficiency with this version is how it treats cons cells that are not proper lists. Note that function listp returns true for all cons cells—even those that do not constitute proper lists—but mapcar does require that its input be a proper list. We can wind up along our "listp true" path, recursively calling on mapcar, and have mapcar fail for receiving an improper list. That means that the algorithm above either would need to test cons cells to see if they're proper lists before handing them to mapcar, perhaps treating those that aren't as leaves (I'm reluctant to say "atoms" here), or be documented that the expected tree structure is made up of proper lists of proper lists.

If you need to accept top-level "trees" that are not necessarily lists themselves, meaning that a lone atom is a valid tree, or nil is a valid tree, you can tear apart the constituent parts of the function above and write one that only uses mapcar after determining that the tree under inspection is a list.

兮子 2024-10-14 14:36:25

如果你写:

 (defun negate (n)
   (if ( > n 0)
     (- 0 n)
     n))

那么你就将你的代码限制为实数。

如果您使用 Common Lisp 提供的原始 negate 函数,它将适用于任何数字:

(mapcar (function -) '(1 2/3 #C(4 5)))     
--> (-1 -2/3 #C(-4 -5))

If you write:

 (defun negate (n)
   (if ( > n 0)
     (- 0 n)
     n))

then you're limiting your code to real numbers.

If instead you use the primitive negate function provided by Common Lisp, it will work on any number:

(mapcar (function -) '(1 2/3 #C(4 5)))     
--> (-1 -2/3 #C(-4 -5))
萤火眠眠 2024-10-14 14:36:25

这就是我要做的。当然,我只考虑数字列表。因此,如果列表不全是数字,它会抛出错误。

(defun negate (list)
      (flet ((negate-number (x)
           (- x)))
    (labels ((negate-helper (list neg-list)
           (if (null list)
               neg-list ; when all elements are considered return neg-list
               (let ((num-or-list (car list)))
             (if (numberp num-or-list)
                 ;; if number then negate it and add it into the new list (i.e. neg-list)
                 (negate-helper (cdr list) (append neg-list (list (negate-number num-or-list))))
                 ;; if list then first negate the sublist
                 (negate-helper (cdr list) (append neg-list (list (negate-helper num-or-list nil)))))))))
      (negate-helper list nil))))

Here's what I would do. Of course, I am considering only numberic lists. So, it would throw errors if the list isn't all numeric.

(defun negate (list)
      (flet ((negate-number (x)
           (- x)))
    (labels ((negate-helper (list neg-list)
           (if (null list)
               neg-list ; when all elements are considered return neg-list
               (let ((num-or-list (car list)))
             (if (numberp num-or-list)
                 ;; if number then negate it and add it into the new list (i.e. neg-list)
                 (negate-helper (cdr list) (append neg-list (list (negate-number num-or-list))))
                 ;; if list then first negate the sublist
                 (negate-helper (cdr list) (append neg-list (list (negate-helper num-or-list nil)))))))))
      (negate-helper list nil))))
枫以 2024-10-14 14:36:25

您可以通过以下过程来实现这一点:

(defun negate (l)"returns a list of multiplication negative of elements of a list l,
                  element of list l to be each numbers for not to type err,
                  and list l may not be a list of atoms."
  (cond
   ((null l) nil)
   ((consp (car l)) (cons (negate (car l))
                          (negate (cdr l))))
   (t (cons (* -1 (car l))
            (negate (cdr l))))))

也可以有另一个版本。我尝试编写一个尾递归程序,但它不完全是tr。

实现了同样的事情,只是它没有给出与原始顺序相同的顺序。我现在无法解决这个问题:

(defun negate (l)
  (negate-aux l '()))

(defun negate-aux (l A)
  (cond
   ((null l) (reverse A));or A
   ((consp (car l)) (cons (negate (car l))
                          (negate-aux (cdr l) A)))
   (t (negate-aux (cdr l) (cons (* -1 (car l)) A)))))

You can achieve this by the following procedure:

(defun negate (l)"returns a list of multiplication negative of elements of a list l,
                  element of list l to be each numbers for not to type err,
                  and list l may not be a list of atoms."
  (cond
   ((null l) nil)
   ((consp (car l)) (cons (negate (car l))
                          (negate (cdr l))))
   (t (cons (* -1 (car l))
            (negate (cdr l))))))

one can also have another version. i have tried to write a tail-recursive procedure, but it is not fully tr.

achieves same thing except it does not give the same order as original one. i can not now fix this:

(defun negate (l)
  (negate-aux l '()))

(defun negate-aux (l A)
  (cond
   ((null l) (reverse A));or A
   ((consp (car l)) (cons (negate (car l))
                          (negate-aux (cdr l) A)))
   (t (negate-aux (cdr l) (cons (* -1 (car l)) A)))))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文