Привет. В данной статье хотелось бы еще разок осветить вопрос объектного программирования на языке Scheme, так, как его рассматривают в книге «Структура и интерпретация компьютерных программ».
Далее предлагаю тем, кто еще ни когда не программировал на Scheme скачать DrRacket и попробовать по шагам пройтись по примерам из данной статьи. Опытные программисты Scheme, Racket… эта статья будет очень скучна, так как написана для новичков и людей, желающих «потрогать» racket.
И так по порядку. Разомнемся для начала в DrRacket IDE.
Создадим новый файл программы. Сохраним его.
Вставим в начале файла директиву указывающую на язык:
#lang racket
Определим функцию:
(define (func1 x) x) ; принимает на вход x, возвращает x
Использовать функцию можно так:
(func1 10) ; результат будет 10
Теперь определим другую функцию:
(define (func2) "func2")
А теперь попробуем определить переменную такую, что она применяет первую функцию ко второй и возвращает вторую функцию:
(define x (func1 func2)) ; теперь x - это объект экземпляра функции func2
Использовать x можно так:
(x) ; вернет стоку "func2"
Тут мы использовали возможность того, что функция может возвращать функции, а их результат можно определить как переменные.
Далее давайте создадим объект, инкапсулирующий в себе внутренние переменные и другие функции:
(define (MyObject fild1 fild2) ; объект у которого при конструировании будут две переменные fild1 и fild2
(define f1 fild1) ; инициализация внутренней переменной f1, с помощью fild1
(define f2 fild2) ; ...
(define (get-f1) f1) ; вернуть значение внутреннего поля f1
(define (get-f2) f2) ; ...
(define (set-f1 x) (set! f1 x)) ; присваиваем f1 значение x
(define (set-f2 x) (set! f2 x)) ; ...
; далее идет самое интересное
(define (dispatch m) ; функция диспетчирования функций в нашем объекте
(cond ((eq? m 'get-f1) get-f1) ; если m равно get-f1, то возвращается функция get-f1
((eq? m 'set-f1) set-f1) ; ...
((eq? m 'get-f2) get-f2) ; ...
((eq? m 'set-f2) set-f2) ; ...
)
)
dispatch) ; тут мы в функции MyObject возвращаем функцию диспетчирования
Ну вот объект определен, теперь сделаем экземпляр объекта MyObject:
(define Obj1 (MyObject " Hello " " world!!! ")) ; теперь Obj1 экземпляр
Далее просто используем экземпляр так как захотим:
(display ((Obj1 'get-f1))) ; тут ф-ия display что-то типа printf, а двойные скобки
; в ((Obj1 'get-f1)) надо писать для того, вычислялась
функция get-f1
(display ((Obj1 'get-f2))) ; аналогично
(newline) ; переход на новую строку
; результатом будет " Hello world!!! "
Создадим новый экземпляр того же объекта:
(define Obj2 (MyObject " Hello " " habra!!! ")) ;
; результат: "Hello Hello habra!!! world!!!"
Попробуем выполнить:
(display ((Obj1 'get-f1)))
(display ((Obj1 'get-f2)))
(newline)
(display ((Obj2 'get-f1)))
(display ((Obj2 'get-f2)))
(newline)
Что меня поразило — каждый экземпляр возвращает одни и теже функции, но их поведение не одинаковое.
; результатом будет "Hello world!!!"
; и "Hello habra!!!"
То есть в Scheme, в отличие от С++, функции берут переменные и функции для вычисления из своего экземпляра.
Данная особенность сильно помогает организации списков функций для изменения внутренних состояний разных экземпляров одного или нескольких объектов:
(define func-list (list (Obj1 'get-f1) (Obj2 'get-f1) (Obj2 'get-f2) (Obj1 'get-f2)))
Распечатаем выполнения каждой функции из этого списка так:
(map (lambda (x) (display (x))) func-list)
; результат: "Hello Hello habra!!! world!!!"
Автор: javamain