Функциональные объекты в SmallTalk (или выполнение блоков без `value:`)
-
29-09-2019 - |
Вопрос
Можно ли отправить анонимное сообщение на объект? Я хочу составить три подобных объекта (подумайте о FP):
" find inner product "
reduce + (applyToAll * (transpose #(1 2 3) #(4 5 6)))
куда reduce
, applyToAll
и transpose
являются объектами и +
, *
и два массива - это аргументы, передаваемые анонимным сообщениям, отправленным этим объектам. Можно ли достичь того же, используя блоки? (но нет явного использования value:
).
Решение
Возможно, то, что вы действительно хотите сделать, это определить DSL внутри SmallTalk?
Другие советы
aRealObject reduceMethod: +;
applyToAll: *;
transpose: #(#(1 2 3) #(4 5 6));
evaluate
будет работать, когда Arealobject определил правильные методы. Где вам нужен блок?
Ты ищешь doesNotUnderstand:
. Отказ Если reduce
это объект, который не реализует +
Но вы все равно отправляете его, тогда вместо этого это doesNotUnderstand:
Метод будет вызван. Обычно это просто вызывает ошибку. Но вы можете переопределить по умолчанию и получить доступ к селектору +
И другой аргумент и делайте с ними все, что вам нравится.
Для простоты создайте класс Reduce
. Отказ На своем классе определите метод:
doesNotUnderstand: aMessage
^aMessage argument reduce: aMessage selector
Тогда вы можете использовать это так:
Reduce + (#(1 2 3) * #(4 5 6))
который в скрипечном рабочем пространстве отвечает 32, как и ожидалось.
Это работает, потому что *
уже реализован для коллекций с подходящей семантикой.
В качестве альтернативы добавить класс ApplyToAll
С этим методом класса:
doesNotUnderstand: aMessage
^aMessage argument collect: [:e | e reduce: aMessage selector]
а также добавить этот метод в SequenceableCollection
:
transposed
^self first withIndexCollect: [:c :i | self collect: [:r | r at: i]]
Тогда вы можете написать
Reduce + (ApplyToAll * #((1 2 3) #(4 5 6)) transposed)
что довольно близко к вашей оригинальной идее.