Почему это так, если это утверждение? - PullRequest
2 голосов
/ 11 апреля 2019

Вопрос состоит в том, чтобы написать функцию, которая берет список и разбивает его на два равных по размеру в одном списке и возвращает список, первый элемент которого является первым списком, а второй элемент - вторым списком.У меня есть код, который делает это, но есть некоторые аспекты, которые я не понимаю.

(здесь часть всего кода)

(define (split l)
  (define (arghelp want num call)
    (if (want num)
        num
        (num (error "No" num want call))))

Почемуесли утверждение не имеет предиката?Я предположил, что если аргумент 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))))

Ответы [ 2 ]

2 голосов
/ 11 апреля 2019

Функция является значением.например.(lambda (v) v) оценивается как функциональный объект.Часто функции связаны с переменными.например.

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

identity - это переменная, такая же, как num, но значения, которые они принимают при оценке переменной, относятся к разным типам.Одна - это функция (она же замыкание, процедура), другая - число.Все переменные могут быть оценены:

+ ; ==> #<procedure:+> 

#<procedure:+> является визуальным представлением основной функции, обычно называемой + в ракетке, и Ракет упоминает имя, даже если имя не имеет значения.Вы можете сделать это:

(определить my-add +) (my-add 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 странный, поскольку он проверяет числа, где, глядя на него, он никогда не будет ничем другим.Он не проверяет, является ли l списком, поэтому мы можем быть уверены, что length не потерпит неудачу.Таким образом, оба вызова для проверки номеров могут быть удалены, и я предлагаю вместо этого:

(assert list? l split)
2 голосов
/ 11 апреля 2019

Почему у оператора if нет предиката?

Да, у него есть предикат:

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

В приведенной выше строке want являетсяФункция получена в качестве параметра.Когда вы позвонили arghelp, вы сделали это следующим образом:

(arghelp integer? p take-help)

Если вы замените аргумент, условие фактически станет следующим:

(if (integer? num) ...

И вот вам предикатискали!

...