Функциональные объекты в Smalltalk (или выполнение блоков без `value:`) - PullRequest
6 голосов
/ 08 ноября 2010

Можно ли отправить анонимное сообщение объекту? Я хочу составить три объекта, как это (подумайте FP):

 " find inner product "
 reduce + (applyToAll * (transpose #(1 2 3) #(4 5 6)))

, где reduce, applyToAll и transpose являются объектами, а +, * и два массива являются аргументами, передаваемыми анонимным сообщениям, отправленным этим объектам. Можно ли добиться того же, используя блоки? (но без явного использования value:).

Ответы [ 3 ]

5 голосов
/ 08 ноября 2010
aRealObject reduceMethod: +; 
            applyToAll: *; 
            transpose: #(#(1 2 3) #(4 5 6));
            evaluate

будет работать, когда aRealObject определит правильные методы.Где вам нужен блок?

3 голосов
/ 18 ноября 2010

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

Для простоты создайте класс Reduce. На стороне класса определите метод:

doesNotUnderstand: aMessage
    ^aMessage argument reduce: aMessage selector

Тогда вы можете использовать это так:

Reduce + (#(1 2 3) * #(4 5 6))

который в рабочем пространстве Squeak отвечает 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)

, что довольно близко к вашей первоначальной идее.

...