読者のみなさんにもgotoのある言語で試すことをオススメします。
再帰呼び出しを再帰呼び出しなしで実現 - 西尾泰和のはてなダイアリー
ということだったので goto も使える Squeak Smalltalk で書いてみました(違うw。
| VERBOSE stack functionResult showAny showMany total3 | VERBOSE := true. stack := OrderedCollection new. functionResult := 0. showMany := nil. "for compiler" showAny := [:x | (x isKindOf: Integer) ifTrue: [ Transcript show: x ] ifFalse: [ showMany value: x ] ]. showMany := [:xs | Transcript show: '['. (1 to: xs size) do: [:i | showAny value: (xs at: i). ] separatedBy: [Transcript show: ', ']. Transcript show: ']' ]. total3 := [:xs | | ENTRYPOINT result i LOOP x RETURNPOINT frame | ENTRYPOINT := thisContext previousPc. result := 0. i := 0. LOOP := thisContext previousPc. i := i + 1. x := xs at: i. VERBOSE ifTrue: [ Transcript show: 'xs:'. showMany value: xs. Transcript show: ', x:'. showAny value: x. Transcript show: ', i:'; show: i; show: ', result:'; show: result; cr; endEntry. ]. (x isKindOf: Integer) ifTrue: [ result := result + x. ] ifFalse: [ stack addFirst: {xs. i. x. result}. xs := x. RETURNPOINT := thisContext previousPc + 10. thisContext pc: ENTRYPOINT. RETURNPOINT. frame := stack removeFirst. xs := frame first. i := frame second. x := frame third. result := frame last. result := result + functionResult ]. i < xs size ifTrue: [thisContext pc: LOOP]. stack isEmpty ifFalse: [ functionResult := result. thisContext pc: RETURNPOINT. ]. result ]. VERBOSE ifTrue: [World findATranscript: nil]. total3 value: #(1 (2 3) 4) "=> 10 "
xs:[1, [2, 3], 4], x:1, i:1, result:0 xs:[1, [2, 3], 4], x:[2, 3], i:2, result:1 xs:[2, 3], x:2, i:1, result:0 xs:[2, 3], x:3, i:2, result:2 xs:[1, [2, 3], 4], x:4, i:3, result:6
goto の動作は簡単のため、戻ってきたい場所のプログラムカウンター(pc)をラベルに模した変数に保持し(LABEL := thisContext previousPc)、必要なときにその pc に飛ぶ(thisContext pc: LABEL)ことで実現しています。
しかしこの方法だと RETURNPOINT の pc は未通過のため保持できないので RETURNPOINT への代入については ENTRYPOINT に戻る前にオフセット値をハードコードして保持しなければならなかった点がちょっと心残りですね。^^;