为什么这个if语句是这样的?

问题描述 投票:2回答:2

问题是编写一个函数,它接受一个列表并将其分成两个大小相同的列表,并返回一个列表,其第一个元素是第一个列表,第二个元素是第二个列表。我有一个代码可以做到这一点,但有些方面我不明白。

(这是整个代码的一部分)

(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))))
scheme racket r5rs
2个回答
2
投票

为什么if语句没有谓词?

是的,它有一个谓词:

(define (arghelp want num call)
  (if (want num)

在上面的行中,want是作为参数接收的函数。当你打电话给arghelp时,你这样做了:

(arghelp integer? p take-help)

如果替换参数,则条件实际上变为:

(if (integer? num) ...

这就是你要找的谓词!


2
投票

函数是一个值。例如。 (lambda (v) v)被评估为一个函数对象。函数通常与变量绑定。例如。

(define identity (lambda (v) v))
(define num 19)

identity是一个变量,与num相同,但是当变量被评估时它们变成的值是不同类型的。一个是函数(也就是闭包,过程),另一个是数字。可以评估所有变量:

+ ; ==> #<procedure:+> 

#<procedure:+>是球拍中通常命名为+的核心功能的直观表示,而球拍则提到名称,即使名称是相关的。你可以这样做:

(定义my-add +)(my-add 1 2 3); ==> 6

Predicate是一个返回布尔值#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)
© www.soinside.com 2019 - 2024. All rights reserved.