如何避免在cond子句LISP中复制代码?

时间:2015-12-17 19:23:06

标签: lisp common-lisp

我应该找到从根到LISP中给定节点的路径。最好使用纯功能方法。

二叉树表示使用子列表,例如: (A (B) (C (D) (E))) - A是根,B是A的左子,C是A的右子,D是C的左子,E是C的右子。

在我看来,应该有一些方法可以避免重复以下函数调用:

(get-path (cadr l) x)

(get-path (caddr l) x)

我是LISP的新手并且我不知道并且似乎无法找到解决方案,但我认为必须有一种纯粹的功能性方法。也许使用lambdas?但不确定如何。我使用了错误的方法吗?任何形式的帮助都非常感谢。

;;; l is the list with the binary tree
;;; x is the node we are looking for
(defun get-path(l x) 
    (cond
            ;; nothing to search for anymore
            ((null l) nil)
            ;; found the node we were looking for
            ;; in this case we return a list containing only x
            ((equal (car l) x) (list x))
            ;; the node was found on the left branch
            ((not(equal (get-path (cadr l) x) nil))
                     (cons (car l) (get-path (cadr l) x)))
            ;; the node was found on the right branch
            ((not(equal (get-path (caddr l) x) nil))
                     (cons (car l) (get-path (caddr l) x))))) 

4 个答案:

答案 0 :(得分:4)

这个怎么样?

one = True
two = False
three = False

typed_input = raw_input("Type here: ")
    #first
if one == True and two == False and three == False:
    if typed_input == "blah":
        do something
        typed_input = raw_input("Type here: ")
        one = False
        two = True
        three = False

    elif "the" in typed_input:
        do something else
        typed_input = raw_input("Type here: ")
        one = False
        two = True
        three = False

你甚至应该定义有意义的命名函数,比如(defun root-path (tree element) (when tree (cons (first tree) (unless (eql (first tree) element) (or (root-path (second tree) element) (root-path (third tree) element) (return-from root-path nil)))))) tree-valueleft-subtree,但这可能是矫枉过正的。

在上文中,请注意right-subtree(resp。when)在条件失败时(resp。成功)用于其unless值。如果您愿意,可以使用nilcond表达式进行翻译。这里唯一的重复是双if值,可以由编译器优化,也可以使用周围的(first tree)绑定进行手动优化。

修改

原始代码无效。解决方案是使用Joshua的答案,但我不会复制粘贴在这里,所以我添加了let表达式。虽然它有效,但您的老师和/或同事可能喜欢这种方法; - )

测试

return-from

答案 1 :(得分:3)

我结合了最后两个cond条款。你想检查左侧,看看那里是否有路径,如果有路径,请抓住它,如果没有,请检查右侧。然后,无论哪一个产生路径(如果有的话),你想要追加到那个。这看起来像这样。首先,为方便起见,有两个功能:

(defun element (tree)
  (first tree))

(defun left (tree)
  (second tree))

(defun right (tree)
  (third tree))

现在,解决方案的真正含义是:

(defun get-path (element tree)
  (cond
    ;;  A null tree is empty and doesn't match anything.
    ((null tree) '())
    ;; If the element of this tree is the element, then we have a
    ;; partial path of length 1: (ELEMENT).
    ((eql element (element tree)) (list element))
    ;; Othweise, let PATH be the path on the left or the path on the
    ;; right, whichever exists.
    (t (let ((path (or (get-path element (left tree))
                       (get-path element (right tree)))))
         ;; If there's no path on either side, then return NIL.
         ;; Otherwise, prepend the current element onto the path that
         ;; exists.
         (if (null path) '()
             (list* (element tree) path))))))

请注意,列表* 缺点的功能相同,但它更清楚地表明您正在使用列表,不只是 cons cells 。您也可以使用缺点

我们可以确认这是按预期工作的:

(defparameter *tree* '(A (B) (C (D) (E))))

(get-path 'c *tree*) ;;=> (A C)
(get-path 'd *tree*) ;;=> (A C D)
(get-path 'f *tree*) ;;=> NIL

答案 2 :(得分:2)

labels用于内部(本地)功能:

(defun get-path(l x)
    (labels ((prepend-path (elt)
                (cons (car l) (get-path elt x))))
        (cond
            ;; nothing to search for anymore
            ((null l) nil)
            ;; found the node we were looking for
            ;; in this case we return a list containing only x
            ((equal (car l) x) (list x))
            ;; the node was found on the left branch
            ((not(equal (get-path (cadr l) x) nil))
                     (prepend-path (cadr l)))
            ;; the node was found on the right branch
            ((not(equal (get-path (caddr l) x) nil))
                     (prepend-path (caddr l))))))

或者,您可以使用flet代替labels,因为您没有相互引用的内部函数。就个人而言,我使用labels并且因为这个原因几乎没有使用flet(加上重新缩进函数的开销。)

答案 3 :(得分:0)

你可以做的是从Common Lisp中的TXR Lisp复制照应condaifa宏。 (源代码在这里;祝你好运!)enter link description here

然后您可以这样写,使用照应get-path变量引用it表达式。

(conda
  ;; nothing to search for anymore
  ((null l) nil)
  ;; found the node we were looking for
  ;; in this case we return a list containing only x
  ((equal (car l) x) (list x))
  ;; the node was found on the left branch
  ((not (equal (get-path (cadr l) x) nil)) (cons (car l) it))
  ;; the node was found on the right branch
  ((not (equal (get-path (caddr l) x) nil)) (cons (car l) it)))

conda对于(not x)(null x)(TXR Lisp中的(false x))表达式非常聪明。如果测试表达式是其中之一,那么它会递归到x执行#34; anaphoric it"。

请注意,it绑定到地方,而不仅仅是it的目标不仅不会被评估多次,如果目标是一个地方,那么it指的是那个地方:

(ifa (< x 10)
  (inc it)) ;; increments x.

ifa的这个方面是在placelet宏的帮助下实现的,它在Common Lisp中不存在。快速而肮脏的替代方法是使用symbol-macrolet。唯一的问题是表示地点的符号宏允许对地点进行多次评估,而placelet只评估一次地点。然后,生成的词汇符号表示存储位置,而不是整体表达式。

ifa旨在与保罗格雷厄姆aif擦拭地板,或者补充它; conda基于ifa(not (equal whatever nil))

顺便说一下,不要写像

这样的表达式
equal

在Lisp中!首先,如果您与nil进行比较,nil平等并不是特别有意义;只有equalnileq,并且这是根据(not (eq whatever nil)) 相等,所以您可能会:{/ p>

eq

其次,对于不是(if (not (eq foo nil)) do-this) ---same-as--> (if foo do-this) 到nil的东西意味着某事是真的。也就是说:

aif

<!/ P>

如果我们重构你的代码以摆脱这些东西,那么如果acond(和基于它的(ifa (not (equal (get-path whatever) nil))) (list it)) 我们有保罗格雷厄姆风格的照应,那就更好了)。也就是说:

(aif (get-path whatever) (list it))

变为:

it

其中ifa通常是整个测试表达式的值,而不是那个表达式中有点巧妙选择的成分。

(ifa (true (get-path whatever)) (list it)) 下,使用以下内容表达的更为详细:

true

(defun true (x) (identity x)). 可以定义为

ifa

如果没有额外的换行,it会将whatever绑定到org.openqa.selenium.firefox.NotConnectedException: Unable to connect to host 127.0.0.1 on port 7055 after 45000 ms. Firefox console output: ddons.xpi DEBUG checkForChanges 1450818781417 addons.xpi DEBUG Loaded add-on state from prefs: {"app-profile":{"fxdriver@googlecode.com":{"d":"C:\\Users\\sluite\\AppData\\Local\\Temp\\anonymous4238069008057039774webdriver-profile\\extensions\\fxdriver@googlecode.com","e":false,"v":"2.45.0","st":1450818779415,"mt":1450818779275}},"app-global":{"{972ce4c6-7e08-4474-a285-3208198ce6fd}":{"d":"C:\\Program Files (x86)\\Mozilla Firefox\\browser\\extensions\\{972ce4c6-7e08-4474-a285-3208198ce6fd}","e":true,"v":"43.0.1","st":1450741870041,"mt":1450322003000}}} 1450818781418 addons.xpi DEBUG Existing add-on fxdriver@googlecode.com in app-profile 1450818781418 addons.xpi DEBUG getModTime: Recursive scan of {972ce4c6-7e08-4474-a285-3208198ce6fd} 1450818781419 addons.xpi DEBUG Existing add-on {972ce4c6-7e08-4474-a285-3208198ce6fd} in app-global 1450818781419 addons.xpi DEBUG getInstallState changed: false, state: {"app-profile":{"fxdriver@googlecode.com":{"d":"C:\\Users\\sluite\\AppData\\Local\\Temp\\anonymous4238069008057039774webdriver-profile\\extensions\\fxdriver@googlecode.com","e":false,"v":"2.45.0","st":1450818779415,"mt":1450818779275}},"app-global":{"{972ce4c6-7e08-4474-a285-3208198ce6fd}":{"d":"C:\\Program Files (x86)\\Mozilla Firefox\\browser\\extensions\\{972ce4c6-7e08-4474-a285-3208198ce6fd}","e":true,"v":"43.0.1","st":1450741870041,"mt":1450322003000}}} 1450818781420 addons.xpi DEBUG No changes found 1450818781426 addons.manager DEBUG Registering shutdown blocker for XPIProvider 1450818781426 addons.manager DEBUG Provider finished startup: XPIProvider 1450818781426 addons.manager DEBUG Starting provider: LightweightThemeManager 1450818781426 addons.manager DEBUG Registering shutdown blocker for LightweightThemeManager 1450818781427 addons.manager DEBUG Provider finished startup: LightweightThemeManager 1450818781427 addons.manager DEBUG Starting provider: GMPProvider 1450818781431 addons.manager DEBUG Registering shutdown blocker for GMPProvider 1450818781431 addons.manager DEBUG Provider finished startup: GMPProvider 1450818781431 addons.manager DEBUG Starting provider: PluginProvider 1450818781431 addons.manager DEBUG Registering shutdown blocker for PluginProvider 1450818781432 addons.manager DEBUG Provider finished startup: PluginProvider 1450818781432 addons.manager DEBUG Completed startup sequence 1450818781497 addons.xpi-utils DEBUG Starting async load of XPI database C:\Users\sluite\AppData\Local\Temp\anonymous4238069008057039774webdriver-profile\extensions.json *** Blocklist::_loadBlocklistFromFile: blocklist is disabled 1450818781568 addons.manager DEBUG Starting provider: <unnamed-provider> 1450818781568 addons.manager DEBUG Registering shutdown blocker for <unnamed-provider> 1450818781568 addons.manager DEBUG Provider finished startup: <unnamed-provider> 1450818781653 addons.xpi-utils DEBUG Async JSON file read took 0 MS 1450818781653 addons.xpi-utils DEBUG Finished async read of XPI database, parsing... 1450818781653 addons.xpi-utils DEBUG Successfully read XPI database 1450818781711 addons.manager DEBUG Starting provider: PreviousExperimentProvider 1450818781711 addons.manager DEBUG Registering shutdown blocker for PreviousExperimentProvider 1450818781712 addons.manager DEBUG Provider finished startup: PreviousExperimentProvider 1450818825183 addons.manager DEBUG shutdown 1450818825183 addons.manager DEBUG Calling shutdown blocker for XPIProvider 1450818825184 addons.xpi DEBUG shutdown 1450818825184 addons.xpi-utils DEBUG shutdown 1450818825184 addons.manager DEBUG Calling shutdown blocker for LightweightThemeManager 1450818825184 addons.manager DEBUG Calling shutdown blocker for GMPProvider 1450818825185 addons.manager DEBUG Calling shutdown blocker for PluginProvider 1450818825186 addons.manager DEBUG Calling shutdown blocker for <unnamed-provider> 1450818825187 addons.manager DEBUG Calling shutdown blocker for PreviousExperimentProvider 1450818825189 addons.xpi DEBUG Notifying XPI shutdown observers 1450818825191 addons.manager DEBUG Async provider shutdown done at org.openqa.selenium.firefox.internal.NewProfileExtensionConnection.start(NewProfileExtensionConnection.java:118) at org.openqa.selenium.firefox.FirefoxDriver.startClient(FirefoxDriver.java:246) at org.openqa.selenium.remote.RemoteWebDriver.<init>(RemoteWebDriver.java:114) at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:193) at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:186) at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:182) at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:95) at WindowsHandle.HandleACLPopUP.baseURL(HandleACLPopUP.java:27) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84) at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:564) at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:213) at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138) at org.testng.TestRunner.beforeRun(TestRunner.java:641) at org.testng.TestRunner.run(TestRunner.java:609) at org.testng.SuiteRunner.runTest(SuiteRunner.java:334) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291) at org.testng.SuiteRunner.run(SuiteRunner.java:240) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224) at org.testng.TestNG.runSuitesLocally(TestNG.java:1149) at org.testng.TestNG.run(TestNG.java:1057) at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111) at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204) at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)