问题是编写一个函数,该函数接受一个列表并将其分成两个相等大小的列表,然后返回一个列表,其第一个元素是第一个列表,第二个元素 是第二个列表。我有一个执行此操作的代码,但是其中有些方面我不理解。
(这是整个代码的一部分)
(define (split l)
(define (arghelp want num call)
(if (want num)
num
(num (error "No" num want call))))
为什么if语句没有谓词?我以为,如果want参数等于num参数,那么代码将运行相同的代码,但是不会。
(如果有帮助,请看完整的代码)
(define (split l)
(define (arghelp want num call)
(if (want num)
num
(num (error "No" num want call))))
(define (take-help lst p)
(arghelp integer? p take-help)
(let next ((lst lst) (p p))
(if (zero? p) '()
(cons (car lst)
(next (cdr lst) (- p 1))))))
(define (drop-help lst p)
(arghelp integer? p drop-help)
(let next ((lst lst) (p p))
(if (zero? p)
lst
(next (cdr lst) (- p 1)))))
(let ((a (quotient (length l) 2)))
(cons (take-help l a)
(drop-help l a))))
答案 0 :(得分:2)
为什么if语句没有谓词?
是的,它有一个谓词:
(define (arghelp want num call)
(if (want num)
在上一行,want
是作为参数接收的函数。当您致电arghelp
时,您是这样做的:
(arghelp integer? p take-help)
如果替换参数,则条件实际上变为:
(if (integer? num) ...
这就是您要查找的谓词!
答案 1 :(得分:2)
函数是一个值。例如。 (lambda (v) v)
被求值到一个函数对象。函数通常绑定到变量。例如。
(define identity (lambda (v) v))
(define num 19)
identity
是一个变量,与num
相同,但是它们在评估变量时变成的值是不同的类型。一个是函数(又名闭包,过程),另一个是数字。可以评估所有变量:
+ ; ==> #<procedure:+>
#<procedure:+>
是球拍中通常命名为+
的核心功能的直观表示,并且Racket提及了该名称,即使该名称是反讽的。您可以这样做:
(定义我的添加+) (我加1 2 3); ==> 6
谓词是一个返回布尔值#f
或#t
的函数,通常它们的变量名以?结尾。按照惯例,但不强制执行。该语言对此没有任何意见,因此实现将其与其他任何函数一样对待。我已经看到谓词不使用约定,而对谓词根本不使用谓词的命名方案则使用了不好的代码。最后一个实际上是两者中最差的。
每当您看到带有括号的变量,例如(want num)
时,您都知道want
是一个函数,并以num
作为参数,或者want
是其他变量,并且程序会惨败。因此,虽然Scheme不进行类型检查,但是当您尝试疯狂(num identity)
之类的方法时,它将失败。您会收到一条错误消息,指出该应用程序运行非常糟糕,因为num
是一个数字而不是一个函数。
代码也一样。程序员也许应该使变量名与暗示它是谓词的建议相一致。这不会丝毫改变代码,但有助于阅读。像这样:
(define (arghelp predicate? value call)
(if (predicate? value)
value
(value (error "Invalid value" value predicate? call))))
这看起来仍然很糟糕。我们知道value
不是它的功能。同样,它的用途是发出错误信号,并且返回的内容并不重要。让我们修复它。我建议应该这样写:
(define (assert predicate? value call)
(when (not (predicate? value))
(error "No" value predicate? call)))
在助手中您看到它确实存在:
(assert integer? p take-help)
我已将该函数重命名为更好的名称。通过使用替换规则,我们知道这与编写相同:
(when (not (integer? p))
(error "No" p integer? take-help)))
现在,您发布的代码split
很奇怪,因为它可以检查frmo所查看的数字,而不会再有其他数字了。它不会检查l
是否为列表,以便我们可以确定length
不会失败。因此,可以删除两个检查号码的电话,我建议改为:
(assert list? l split)