【问题标题】:Scheme homework help计划作业帮助
【发布时间】:2010-03-25 23:59:06
【问题描述】:

好的,我在课堂上开始学习一门新语言。我们正在学习 Scheme,我不确定如何去做。当我说学习一门新语言时,我的意思是扔了一份家庭作业,并被告知要弄清楚。其中一些让我很难过。

我的第一个问题是:

如果参数是一个包含 n a 后跟 n b 的列表,则编写一个返回 true(布尔常量 #t)的 Scheme 函数。否则为假。

这是我现在拥有的:

(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)))))))))))

我知道这是完全错误的,但我一直在努力,所以请放轻松。任何帮助将不胜感激。

【问题讨论】:

  • @Coronatus 你没见过 lisp?
  • @Bryan 不,我不是恐龙……
  • 你知道方案吗?我不知道这是否正确,但我看到的所有示例看起来都像这样。
  • 方案仍然是加州大学伯克利分校 CS 入门课程的首选语言
  • 你有 lambda 拼写错误。

标签: scheme


【解决方案1】:

我从 Essentials of Programming Languages 中学到的一个技巧是始终通过首先处理两个重要情况来编写递归列表函数:null(列表结尾)和 not null。

所以,列表函数的基本结构如下所示:

(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,但哪个?空列表是否具有与b 相同数量的a?

接下来,您需要对递归案例做一些事情。您的基本方法非常好(尽管您的示例代码是错误的):当您看到 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 与 'b 测试,您需要

(if (eq? 'a (head tail)) ...)
; not
(if (= 'a (head tail)) ...)

我希望这会有所帮助。我想我给了你所有的片段,虽然我跳过了一些东西。您现在需要更改 null 大小写以检查计数。如果最后不是= 0,则答案为假。

您还应该维护一个单独的标志变量,以确保在切换到 'b 后,如果您看到另一个 'a,则返回 #f。这样'(a a a b b a b b) 这样的列表就不会误传。以与我在上面添加 counter 相同的方式添加标志,方法是添加另一个函数参数并在每次递归调用时传递值。

最后,如果你的老师真的没有给你任何帮助,也不会,那么你可能想读一本关于 Scheme 的基础书籍。我自己没有用过这些,但我听说它们很好:The Scheme Programming Language、How to Design Programs 或 err umm 我以为网上有第三本书是免费的,但我现在找不到。我想如果你有很多额外的时间并且想大开眼界,你可以阅读Structure and Interpretation of Computer Programs。它教了一点 Scheme 和很多关于编程语言的知识。

*它确实有一些这样的东西,但最好暂时忽略它们。

【讨论】:

  • 很好,但基本情况不应该总是返回 #f 或 #t - 只有当您期望递归返回布尔值时才有意义。如果它是 int,则 0 通常是基本情况,或者其他类型的其他情况。你真的只需要弄清楚每个功能的正确选择。
  • 我同意阅读计算机程序的结构和解释的建议。我还保留着我在伯克利读本科时的副本。这是一本好书。
【解决方案2】:

list不是关键字吗?我总是使用“alist”作为我的变量名来绕过它。

你可以像你一样使用计数器,但我可能会使用具有以下条件的递归函数:

参数:列表

如果列表为 nil,则返回 true,

如果第一个元素不是a,则为false,

如果最后一个元素不是 b,则为 false,

(aequalb (reverse (cdr (reverse (cdr alist))))) ;;挑出前后,递归

在这种情况下,您可能需要编写一个反向函数...不记得它是否已经存在了。


另外,从语法的角度来看,你不需要引入 lambda 表达式...

(define (foo arg) (+ 1 arg))

是一个名为 foo 的函数,它接受一个数字,然后将其加一。你可以称之为 (foo 1)

【讨论】:

  • 你们以前做过递归吗? (我猜是的,因为你尝试使用它)
  • 其实没教过,这不是程序课,而是程序原理课,所以他只是布置了一种语言的作业。我所知道的一切都是通过查找示例。
  • 不,list 可以重复使用,唯一不能在 Scheme 中重新定义的符号是 define。我知道,我试过了。 :)
【解决方案3】:

我会看看andmap、take 和drop,它们(在它们之间)使这变得非常简单。哦,至少现在,我可能会尝试忘记let 甚至存在。并不是说它有什么特别的问题,但我猜你会遇到的大多数问题(至少在一段时间内)不需要/不会需要它。

【讨论】:

    【解决方案4】:

    这是一个可能对您有所帮助的首发。它处理了基本问题,尽管您需要进行测试以确保没有边缘情况。

    无论如何,该函数会检查几个条件:

    • 它首先检查一个基本情况(递归函数需要有这个,以避免无限递归的可能性)。如果输入列表为空,则返回 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"))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多