通用LISP(SBCL):从循环内返回值 [英] Common LISP (SBCL): Returning values from within loops

查看:203
本文介绍了通用LISP(SBCL):从循环内返回值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前言:我目前正在上一门简明课程,显然是用LISP讲授的,而且我一生中从未与LISP一起工作过,所以我不得不在一个周末学习这种语言.我对于深渊的代码提前表示歉意.我只是对LISP的语法非常熟悉,可以使代码正常工作.

Preface: I'm currently taking a condensed course that is apparently taught in LISP and I've never worked with LISP in my life so I had to learn the language over a weekend. I apologize in advance for the abysmal code. I'm just familiar enough with LISP's syntax to get the code working and not much more.

我目前正在开发一个解决地图着色问题的程序.该代码采用一个序列,其中每个子序列的第一个元素是状态,第二个元素代表一种颜色.例如:'(((A R)(B G)(C G)(D Y)(E B)(F B)),然后检查以确保没有任何状态具有与其所约束的状态相同的颜色(由约束列表定义).我知道可能有很多更简洁的方法来执行此操作,但是我目前正在努力的是让我的dolist循环在遇到if语句时立即返回值T.到目前为止,我一直无法获得仅返回值的函数,而不得不采用这种非常丑陋/错误的方法,即将变量设置为true并等待循环完成才能使代码正常工作.我已经尝试过使用return,并且在if语句中只包含T,但是在两种情况下,循环都将完成而不是返回一个值,我也不知道为什么.

I'm currently working on a program that solves the map coloring problem. This code takes a sequence where the first element of each sub sequence is a state and the second element represents a color. ex: '((A R) (B G) (C G) (D Y) (E B) (F B)) and then checks to make sure that no state has the same color as a state it's constrained by (defined by the constraint list). I know there are probably a lot of cleaner and simpler ways to do this but what I'm currently struggling with is having my dolist loops immediately return the value T whenever the if statement is met. So far I've been unable to get the functions to simply return a value and had to resort to this really ugly/wrong method of setting a variable to true and waiting for the loop to finish in order to make the code work. I've tried using return and just having T inside the if statements but, in both cases, the loop would finish instead of returning a value and I have no idea why.

(setq constraint '((A (B C E)) (B (A E F)) (C (A E F)) (D (F)) (E (A B C F)) (F (B C D E))))

(defun check_constraint (f s)
    (setf ans nil)
    (dolist (state constraint)
        (if (eq (first state) f)
            (if (search (list s) (second state))
                (setf ans T) ;;where I want it to just return T
            )
        )
    )
    ans
)

;;ex: ((A R) (B R)  (C B)  (D R)  (E B)  (F G))
(defun check_conflict (lst)
    (setf anb nil)
    (dolist (state lst)
        (dolist (neighbor (remove state lst))
            (if (check_constraint (first state) (first neighbor))
                (if (eq (second state) (second neighbor))
                    (setf anb T)) ;;where I want it to just return T
            )
        )
    )
    anb
)

我最终只是通过递归解决了这个问题.该代码现在更干净了,但是我仍然很想知道我的问题是什么.这是递归代码.

I ended up just fixing this with recursion. The code is cleaner now but I'd still love to know what my issue was. This is the recursive code.

(setq constraint '((A (B C E)) (B (A E F)) (C (A E F)) (D (F)) (E (A B C F)) (F (B C D E))))

(defun check_constraint (lst f s)
    (COND
        ((null lst) nil)
        ((search (list (car (car lst))) f)
            (if (search s (second (car lst))) T))
        (t (check_constraint (cdr lst) f s))
    )
)

(defun check_neighbor (check lst)
    (COND
        ((null lst) nil)
        ((check_constraint constraint (list (car check)) (list (first (first lst))))
            (if (eq (second check) (second (car lst))) T))
        (t (check_neighbor check (cdr lst)))
    )
)

;;(check_state '((A R) (B R) (C B) (D R) (E B) (F G)))
(defun check_state (lst)
    (COND
        ((null lst) nil)
        ((check_neighbor (car lst) (cdr lst)) T)
        (t (check_state (cdr lst)))
    )
)

推荐答案

首先是一些样式问题.您应该使用 DEFVARDEFPARAMETER 声明全局变量.这些名称的名称周围也应带有星号,以表明它们具有全局性(或实际上是特殊的).

First a few style issues. You should use DEFVAR or DEFPARAMETER to declare global variables. Those should also have asterisks around the name to show that they are global (or special actually).

(defparameter *constraint*
  '((A (B C E))
    (B (A E F))
    (C (A E F))
    (D (F))
    (E (A B C F))
    (F (B C D E))))

命名事物的惯用习惯是在单词之间使用破折号(CHECK-CONSTRAINT而不是CHECK_CONSTRAINT).您还应该使用完整的单词代替变量名(用LIST代替LST)代替变量名.右括号不应写在自己的行上.

The lisp convention for naming things is to use dashes between words (CHECK-CONSTRAINT instead of CHECK_CONSTRAINT). You should also prefer full words for variable names instead of abbreviations (LIST instead of LST). The closing parentheses should not be written on their own line.

然后是实际问题.您可以使用 RETURN 从名为NIL.循环建立了这样一个块,因此您可以编写第一个函数

Then the actual problem. You can use RETURN to return a value from a block named NIL. Loops establish such a block, so you can write the first function like

(defun check-constraint (first second)
  (dolist (state *constraint*)
    (when (and (eq first (first state))
               (member second (second state)))
      (return t))))

当只有一个分支时,最好使用WHEN而不是IF.我还使用AND将两个IF组合为一个.因为您将S包装在使用SEARCH的列表中,所以我认为您可能想使用MEMBER来代替(尽管我不确定,因为我不完全知道代码应该做什么).如果有误,您可以改回来.

It's better to use WHEN instead of IF when there's only a then-branch. I also combined the two IFs into one using AND. Since you were wrapping S in a list for using SEARCH, I figured you probably want to use MEMBER instead (although I'm not sure since I don't exactly know what the code is supposed to do). You can change that back if it's wrong.

您可能还可以将其简化为

You probably could also simplify it to

(defun check-constraint (first second)
  (member second (second (find first *constraint* :key #'first))))

在第二个函数中,您有两个循环.如果使用RETURN从内部循环返回,则最终将继续外部循环并忽略返回值.因此,您必须使用 RETURN-FROM 从函数中返回而不是内循环.

In the second function you have two loops. If you use RETURN to return from the inner one, you just end up continuing the outer loop and ignoring the return value. So you have to use RETURN-FROM to return from the function instead of the inner loop.

(defun check-conflict (list)
  (dolist (state list)
    (dolist (neighbor (remove state list))
      (when (and (check-constraint (first state) (first neighbor))
                 (eq (second state) (second neighbor)))
        (return-from check-conflict t)))))

这篇关于通用LISP(SBCL):从循环内返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆