Ошибка определения метода класса как выражения - PullRequest
1 голос
/ 09 февраля 2020

Я пытаюсь определить метод класса следующим образом:

#lang racket
(define foo% (class object%
  (super-new)
  (define/public plus-one (curry + 1))))

Но этот код выдает следующую ошибку: eval:2:0: class: bad form for method definition

Согласно документации Racket, это должно быть возможно определить метод с использованием синтаксиса (define/public id expr), поэтому я не понимаю, почему это не работает.

Конечно, есть простой обходной путь с использованием синтаксиса (define/public (id . formals) body ...+), но я бы хотел чтобы понять, почему текущий код не принят.

Ответы [ 2 ]

0 голосов
/ 09 февраля 2020

В документации для class* см. Нетерминалы с именами определение метода и метод-процедура . Они описывают ограничения на определение легального метода. Позже в параграфе class документов говорится, что каждое объявление private, public, et c должно соответствовать определению метода . Так что это не ошибка, это предполагаемое поведение.

Кстати, причина такого поведения в том, что макрос Racket class реализует методы, переписывая метод lambda (или case-lambda ) выражение (я) для добавления неявного аргумента для this. Этот же аргумент также неявно используется для доступа к публичным c и частным полям объекта. Ограничение определений методов определенными фигурами позволяет найти правильные выражения lambda для корректировки.

Вот один из способов переписать ваш пример:

#lang racket
(define do-plus-one (curry + 1))
(define foo% (class object%
  (super-new)
  (define/public (plus-one n) (do-plus-one n)))

Это имеет следующие приятные свойства: do-plus-one вычисляется только один раз, и для каждого foo% объекта не требуется слот для поля.

0 голосов
/ 09 февраля 2020

Это может быть ошибка. Представьте, что у нас есть обычный путь:

(define/public (plus-one n) (+ 1 n))

Способ define с именем и аргументами в скобках - это сахар для id и lambda, и он работает:

(define/public plus-one (lambda (n) (+ 1 n)))

Я получаю, что (curry + 1) возвращает аналогичную лямбду и что этот объект должен работать, но это не так.

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

Если вы представили, что мы использовали закрытую переменную для приращения, которое вы не могли бы использовать curry, так как оно кеширует ее. например. Вы не можете повторить это:

(define increaser%
  (class object%
    (init inc)
    (define increment inc)
    (super-new)
    (define/public (set-inc inc)
      (set! increment inc))
    (define/public (increase n)
      (+ increment n))))

(define test (new increaser% [inc 2]))
(send test increase 1) ; ==> 3
(send test set-inc 3)
(send test increase 1) ; ==> 4
(define test2 (new increaser% [inc 21]))
(define value 13)
(map (lambda (obj) (send obj increase value)) (list test test2))
; ==> (16 34)
...