好的,所以我在课堂上开了一门新语言。我们正在学习Scheme,我不知道该怎么做。当我说学习一门新语言时,我的意思是抛出一份功课并告诉他们弄明白。他们中的一些让我难过。
我的第一个问题是:
如果参数是包含n a后跟n b的列表,则编写一个返回true的函数(布尔常量#t)。否则就是假的。
这就是我现在所拥有的:
(define aequalb
(lambda (list)
(let ((head (car list)) (tail (cdr list)))
(if (= 'a head)
((let ((count (count + 1)))
(let ((newTail (aequalb tail))))
#f
(if (= 'b head)
((let ((count (count - 1)))
(let ((newTail (aequalb tail))))
#f
(if (null? tail)
(if (= count 0)
#t
#f)))))))))))
我知道这是完全错误的,但我一直在努力,请放轻松我。任何帮助将不胜感激。
答案 0 :(得分:2)
我从Essentials of Programming Languages中学到的一个技巧是始终通过首先处理两个重要的情况来编写递归列表函数:null(列表的结尾)而不是null。
因此,list函数的基本结构如下所示:
(define some-list-function
(lambda (list)
(if (null? list)
#f
(do-some-work-here (head list)
(some-list-function (tail list))))))
通常你(1)检查null(2)在头上做一些工作,(3)在尾部重复。
您需要做的第一件事是确定空列表的答案。它是#t或#f,但是哪个?空列表与a
具有相同数量的b
吗?
接下来,您需要对递归案例做一些事情。你的基本方法非常好(虽然你的示例代码是错误的):当你看到a
时保持计数上升,当你看到b
时保持计数下降。问题是如何跟踪计数。 Scheme没有循环*因此您必须使用递归执行所有操作。这意味着你需要传递一个额外的计数器变量。
(define some-list-function
(lambda (list counter)
(if (null? list)
; skip null's code for a second
现在您必须决定头部是否为'a
,如果是,则增加count
(否则减少)。但是没有计数变量,只是在函数之间传递。那怎么办呢?
嗯,你必须在线更新它,如下:
(some-list-function (tail list) (+ 1 count))
顺便说一下,除了数字之外,不要使用=
。更新,更酷的Lisps允许它,但Scheme要求您使用eq?
表示符号,=
表示数字。因此,对于'a
vs 'b
测试,您需要
(if (eq? 'a (head tail)) ...)
; not
(if (= 'a (head tail)) ...)
我希望这会有所帮助。我想我给了你所有的东西,虽然我跳过了一些东西。您需要立即更改null case以检查计数。如果最后不是= 0
,答案是错误的。
您还应该维护一个单独的标记变量,以确保在切换到'b
后,如果您看到另一个#f
,则会返回'a
。这样,'(a a a b b a b b)
之类的列表就不会错误传递。添加标记的方式与我在上面添加counter
的方式相同,方法是添加另一个函数参数并在每次递归调用时传递值。
最后,如果你的老师真的没有给你任何帮助,也不会,那么你可能想读一本关于Scheme的基础书。我自己没有使用过这些,但我听说它们很好:The Scheme Programming Language,How to Design Programs或者错误我认为有第三本免费在线书,但我不能现在找到它。我想如果你有更多的额外时间并想要打扰你,你可以阅读Structure and Interpretation of Computer Programs。它讲授了一个关于编程语言的小方案。
*它确实有一些这样的东西,但现在最好忽略它们。
答案 1 :(得分:1)
列表不是关键字吗?我总是习惯使用“alist”作为我的变量名来绕过它。
你可以像你一样使用计数器,但我可能会选择具有以下条件的递归函数:
params:alist 如果列表为nil,则返回true,
如果第一个元素不是a,则为false,
如果最后一个元素不是b,则为false,
(aequalb(反向(cdr(反向(cdr alist)))));;挑选正面和背面,并递归
在这种情况下,您可能需要编写一个反向函数...不记得它是否已存在。
此外,从语法角度来看,您不需要引入lambda表达式...
(define (foo arg) (+ 1 arg))
是一个名为foo的函数,接受一个数字,并为其添加一个。你会称之为(foo 1)
答案 2 :(得分:1)
我会看一下andmap
,take
和drop
,它们之间(它们之间)使这个变得非常微不足道。哦,至少现在,我可能会忘记let
甚至存在。并不是说它有什么特别的错误,但我猜你要获得的大部分问题(至少暂时不会)不会/不需要它。
答案 3 :(得分:0)
这是可以帮到你的第一个切入点。它处理基本问题,但您需要进行测试以确保没有边缘情况。
无论如何,该功能检查了几个条件:
它首先检查一个基本情况(递归函数需要有这个,以避免无限递归的可能性)。如果输入列表为空,则返回true(假设所有项目都已删除,所以此时我们已完成)。
然后代码会检查第一项是a
,最后一项是b
。如果是这样,它会剥离这些字符并进行递归。
否则出现问题,因此函数返回false
(define (aeqb items)
(cond
((equal? '() items) #t)
((and (equal? "a" (car items))
(equal? "b" (car (reverse items))))
(aeqb (cdr (reverse (cdr (reverse items))))))
(else #f)))
(aeqb '("a" "a" "b" "b"))