LISP:为什么我不能在空列表中使用cons?

时间:2016-03-13 23:59:43

标签: lisp common-lisp

我正在尝试通过添加到空列表来构建一个唯一的元素列表,使用LISP中的以下代码:

    <application
        android:name=".VolleyController"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ProductDetail"
            android:parentActivityName=".MainActivity"
            >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.curtrostudios.testapp.MainActivity" />
        </activity>
        <activity android:name=".Comments"
            android:parentActivityName=".ProductDetail"
            >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.curtrostudios.testapp.ProductDetail" />
        </activity>
    </application>

当我调用(makeset'(abbacdba))时,这个特殊的代码导致NIL - 它应该导致(abcd),而不考虑顺序) - 但它看起来像我应该从SET1添加一个原子每次迭代都没有在UNIQ中。你能不能添加到do循环中声明的空列表,还是我还有其他一些问题?顺便说一句,我正在使用clisp。

2 个答案:

答案 0 :(得分:5)

<强> 1。使用正确的格式

在询问Common-Lisp时,请使用正确的格式。 例如,请参阅通过Google搜索"common lisp formatting conventions"返回的前三页。

以下是适用于您的功能的传统格式示例:

;;; Memset - return T if an atom is a top-level member of a set, else NIL
;;; This is needed for the makeset function

(defun memset (atm l)
  (cond ((null l) nil)
        ((eql atm (car l)) t)
        (t (memset atm (cdr l)))))

(defun makeset (set1)
  (do ((uniq ()))
      ((null set1) uniq)
    (cond ((not (memset (car set1) uniq))
           (push (car set1) uniq)))
    (setf set1 (cdr set1))))

<强> 2。尽可能使用原始函数

你的两个函数在Common-Lisp中都是原始的。

remove-duplicates返回没有重复元素的列表,member检查元素是否属于集合。

第3。功能中的错误

如果您仍想使用您的功能,而不是remove-duplicates,则问题就在于此。

如果要修改列表,则应使用修改某些内容的函数。 cons函数会构建一个新对,但 不会修改任何内容。因此,在您的表单(cons (car set1) uniq)中,您可以向uniq添加一个新元素,因为您获得了一个新列表,其中(car set1)作为第一个元素,并且{ {1}}作为列表的其余部分,但是这个新列表会被立即丢弃,因为它没有分配给任何内容。

您可以使用宏setf以这种方式将新值分配给局部变量unique来更改此值:

uniq

或者您可以通过使用宏push编写等效表单:

(setf uniq (cons (car set1) uniq))

最后,请注意(push (car set1) uniq) 函数中的cond可以用更简洁的makeset替换,从而产生此函数:

when

答案 1 :(得分:1)

所有更新都可以使用DO中的步进表单完成。无需PUSHSETF

(defun makeset (set1)
  (do ((uniq nil (if (memset (car set2) uniq)
                      uniq
                    (cons (car set2) uniq)))
       (set2 set1 (cdr set2)))
      ((null set2) uniq)))