Методы и свойства в схеме: возможно ли ООП в схеме? - PullRequest
4 голосов
/ 02 июня 2010

Я буду использовать простой пример, чтобы проиллюстрировать мой вопрос. В Java, C или любом другом языке ООП я мог бы создать класс pie способом, подобным следующему:

class Apple{
    public String flavor;
    public int pieces;
    private int tastiness;
    public goodness(){
        return tastiness*pieces;
    }
}

Какой лучший способ сделать это со Схемой? Я полагаю, я мог бы сделать что-то вроде этого:

(define make-pie
  (lambda (flavor pieces tastiness)
    (list flavor pieces tastiness)))

(define pie-goodness
  (lambda (pie)
    (* (list-ref pie 1) (list-ref pie 2))))

(pie-goodness (make-pie 'cherry 2 5))

;output: 10

... где вишня - это вкус, 2 - это кусочки, а 5 - вкус. Однако тогда нет никакой безопасности типов или видимости, и все просто помещено в немаркированный список. Как я могу улучшить это?

Sidenote: процедура make-pie ожидает 3 аргумента. Если я хочу сделать некоторые из них необязательными (как я мог бы сделать в языках с фигурными скобками, таких как Java или C), целесообразно ли просто принимать аргументы в виде списка (то есть обрабатывать аргументы как список - не требуется ли один аргумент, который является списком) и обрабатывать их таким образом?


Обновление:

Я получил пару ответов со ссылками на различные расширения / библиотеки, которые могут удовлетворить мою потребность в ООП в схеме. Это полезно, так что спасибо.

Однако, хотя я, возможно, и не сообщил об этом хорошо, мне также интересно, как лучше реализовать описанный выше объект pie без таких классов или библиотек, чтобы я мог лучше понять лучшие практики схем.

Ответы [ 4 ]

8 голосов
/ 02 июня 2010

В некотором смысле, замыкания и объекты эквивалентны , так что это, безусловно, возможно. * * * * * * * * * * * * * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * - лучшая проблема для * Scheme .

С другой стороны, если это учебное упражнение, вы можете даже свернуть свое собственное, используя эквивалентность объекта замыкания. (Прошу прощения за любые ошибки, моя схема довольно ржавая.)

(define (make-pie flavor pieces tastiness)
        (lambda (selector)
                (cond ((eqv? selector 'flavor) flavor)
                      ((eqv? selector 'pieces) pieces)
                      ((eqv? selector 'tastiness) tastiness)
                      ((eqv? selector 'goodness) (* pieces tastiness))
                      (else '()))))

Это простой конструктор для pie объекта. Переменные параметров flavor, pieces и tastiness закрываются лямбда-выражением, становясь полями объекта, и первым (и только для простоты здесь) аргументом к закрытию является селектор метода.

Это сделано, вы можете создать экземпляр и ткнуть в некоторых:

> (define pie1 (make-pie "rhubarb" 8 4))
> (define pie2 (make-pie "pumpkin" 6 7))
> (pie1 'flavor)
"rhubarb"
> (pie1 'goodness)
32
> (pie2 'flavor)
"pumpkin"
4 голосов
/ 02 июня 2010

Многие Схемы позволяют вам определять классы, которые содержат поля и методы. Например, см .:

1 голос
/ 06 июля 2016

Вот как я бы порекомендовал реализовать это:

(define PersonClass (lambda (name age strength life)
    (let ((name name)(age age) (life life) (strength strength))
        (lambda (command data)
        (cond
            ((< life 1)
            "I am dead")
            ((equal? command "name")
            name)
            ((equal? command "age")
            age)
            ((equal? command "birthday")
            (set! age(+ age 1)))
            ((equal? command "receive damage")
            (begin (set! life(- life Data)) (display "I received damage\n")))
            ((equal? command "hit")
            (data "receive damage" strength))
            )))))

Используйте это так: (Karl "name" 0)

0 голосов
/ 20 сентября 2018

Большинство схем поддерживают записи SRFI-9 или аналогичные записи R7RS, а R6RS также предоставляет записи с немного другим синтаксисом. Эти записи являются способом создания новых типов в схеме. Кроме того, большинство схем вместе с R6RS и R7RS поддерживают модули или библиотеки, которые являются одним из способов инкапсуляции операций с такими типами.

Многие программисты схем используют их вместо ООП для написания своих программ, в зависимости от характера приложения. Запись предоставляет тип и его поля; предоставляется связанная процедура, которая создает новые объекты этого типа; другие процедуры, которые принимают запись в качестве аргумента (обычно первый аргумент), обеспечивают необходимые операции над типом; и определение модуля / библиотеки определяет, какие из них экспортируются в код пользователя, а какие являются частными для реализации модуля / библиотеки.

Если поле записи само по себе является процедурой, оно может также содержать закрытые данные в качестве замыкания: но часто требуется использовать определение модуля для сокрытия и инкапсуляции данных, а не замыканий (это также обычно более эффективно).

...