2016-04-03 7 views
1

Я хочу, чтобы определить блок и назвать его таким образом:Невозможно вызвать «функцию» в GNU Smalltalk

add := [ :a :b | 
    ^(a+b). 
]. 

n := add value: 1 value: 2. 

Но когда я пытаюсь это, я получаю сообщение об ошибке:

$ gst 3.1.st 
Object: 3 error: return from a dead method context 
SystemExceptions.BadReturn(Exception)>>signal (ExcHandling.st:254) 
SystemExceptions.BadReturn class(Exception class)>>signal (ExcHandling.st:151) 
SmallInteger(Object)>>badReturnError (Object.st:1389) 
UndefinedObject>>executeStatements (3.1.st:3) 

Как можно ли вызвать функцию в GNU Smalltalk?

Ну, я сбросил инструкцию return, и этот код работает нормально. Но когда я пытаюсь определить более сложную функцию, например:

nod := [ :a :b | 
    (a=b) ifTrue: [a]. 
    (a>b) ifTrue: [nod value: (a-b) value: b]. 
    (a<b) ifTrue: [nod value: a value: (b-a)]. 
]. 

n := nod value: 1 value: 2. 
n printNl. 

Он печатает ноль. И если я определяю с помощью «раннего выхода»:

Это дает мне ту же ошибку: возврат из контекста мертвых методов.

Я решить эту проблему таким образом:

nod := [ :a :b | 
    (a=b) ifTrue: [ 
     a 
    ] ifFalse: [ 
     (a>b) ifTrue: [nod value: (a-b) value: b] ifFalse: [nod value: a value: (b-a)]. 
    ] 
]. 

n := nod value: 1 value: 2. 
n printNl. 

Но я думаю, это не красивый способ.

+1

Для удовольствия, вы можете играть с Somthing как этот HTTP: // StackOverflow.com/questions/7547750/smalltalk-block-can-i-explicitly-set-the-return-value-and-stop-executing-th/11532045 # 11532045 –

ответ

4

Отменить оператор возврата (^) с вашего кода, и он будет работать нормально.

В smalltalk, возвращающий завершает метод, в котором появляется оператор return. Он используется для ранних выходов, например a < b ifTrue: [^a] ifFalse:[^b].

В этом случае вы не хотите, чтобы блок вышел из содержащего метода, вы просто хотите, чтобы он что-то оценил при отправке его value:value:. Блок оценивает последний оператор в нем, поэтому просто делайте его регулярным утверждением, и он будет делать трюк.

Сообщение об ошибке, которое вы получили, кстати, также объясняет проблему: вы пытаетесь вернуть 3 из уже мертвого метода.

+0

Спасибо за объяснение! Оно работает! – DmitriyM

+0

Ох ... Не совсем :(Я обновляю свой вопрос. – DmitriyM

+1

@DmitriyM относительно вашего редактирования - способ, которым вы пробовали в прошлом, - это способ сделать это, это определенно самый маленький подход к использованию. Ваша попытка с последовательными утверждениями 'ifTrue' неверно, на самом деле, 1-й и 2-й блоки в реализации 'nod' не имеют побочного эффекта и поэтому бессмысленны. Помните, что это только последний оператор, который возвращается, а последний оператор является последним' ifTrue'. – Oak

4

Удалить нелокальное возвращение (^), скобки и период внутри блока. И попробуйте сделать это снова.

3

Вы уже приняли ответ на свой первоначальный вопрос, а затем повторно определили свой вопрос.

Чтобы ответить на ваш обновленный вопрос, вы можете использовать тот факт, что блок возвращает значение своего последнего утверждения, и использовать локальную переменную:

nod := [ :a :b | |r| 
    (a = b) ifTrue: [r := a]. 
    (a > b) ifTrue: [r := nod value: (a-b) value: b]. 
    (a < b) ifTrue: [r := nod value: a value: (b-a)]. 
    r 
]. 

Мне любопытно, хотя, о контексте. Я подозреваю, что это может быть более точно определено как селектор/метод для класса.


Кстати, вышеупомянутая реализация перейдет в бесконечную рекурсию, если любой из аргументов отрицательный.

Самый простой способ, чтобы получить результаты вы после этого будет:

nod := [ :a :b | a gcd: b ]. 

:)

+0

Nice решение! Большое спасибо! – DmitriyM