Ruby
Smalltalk
クイズ
Pharo
Squeak

【クイズ】Pharo/Squeak Smalltalk の (6 + (1 to: 12)) squared sum の Ruby への直訳、(6 + (1..12)).squared.sum #=> 2018 が動作するようにモンキーパッチを当てよ

t/o

解説

Squeak Smalltalk やその派生である Pharo には APLっぽい配列演算が組み込みの機構として用意されています。

(6 + (1 to: 12)) squared sum "=> 2018 "

ちなみに本家の APL では同じことを次のように書くことができます。

+/(6+⍳12)*2

https://tio.run/##SyzI0U2pTMzJT////1HvXAXHAB@uR31TH7VN0NbXMNN@1LvZ0EhTy@j/fwA

念のため ⍳(iota) は 1 から与えられた値までの数列を、+/ は要素の合計を返します。あと、APL では * を乗算ではなく累乗をあらわすのに使うようです。

ヒント

当該機構は他の Smalltalk、例えば GNU Smalltalk には無いので、次のように(足りないメソッドを含めて)補ってやらないと件の式はここでの期待通りには機能しません。(GNU Smalltalk は他の Smalltalk には無い、クラス名 extend []メッセージパターン [] でクラス拡張やメソッド定義が可能な構文を持っています。為念)

Interval extend [
    generality [ ^ 300 ]
    coerce: aNumber [ ^ Array new: self size withAll: aNumber ]
]

Array extend [
    + other [ ^ self with: other collect: [:x :y | x + y] ]
    squared [ ^ self collect: [:x | x * x] ]
    sum [ ^ self inject: 0 into: [:acc :x | acc + x] ]
]

(6 + (1 to: 12)) squared sum displayNl "=> 2018 "

https://ideone.com/MgwIOX

これが、クイズを解くのに参考になるようなならないようなヒントです。

なお、Ruby は Smalltalk 同様、通常の言語の演算子もレシーバーのクラスに定義されたメソッドにすぎないので、(1..12) + 6 ではなく 6 + (1..12) とすることで難易度を上げてみました。

解答例

class Range
    def coerce(n)
        [(first+n..last+n).to_a, []]
    end
end

class Array
    def squared
        map{ |x| x**2 }
    end
end

p (6 + (1..12)).squared.sum #=> 2018

2.4 より前の Ruby では sum も別途定義が必要です。

https://ideone.com/O2YmtL

もとより、ケント・ベックの仮実装ばりに酷いコードですので、あとの改良はお任せします。^^;

追記:もう少しまともにした版

class Range
    def coerce(n)
        case caller[0].match(/`(.*)'/)[1]
        when "-"
            [self.class.new(-last, -first, exclude_end?), -n]
        else
            [self, n]
        end
    end

    def +(n); first+n..last+n end
    def -(n); first-n..last-n end
    def *(n); (first*n..last*n).step(n) end
end

module Enumerable
    def squared
        map{ |x| x**2 }
    end
end

p (6 + (1..12)).squared.sum #=> 2018 
p (6 - (1..12)).squared.sum #=> 146 
p (6 * (1..12)).squared.sum #=> 23400 
p ((1..12) + 6).squared.sum #=> 2018 
p 6 - (1..12) #=> -6..5 
p (1..12) - 6 #=> -5..6 
p ((1..12) - 6).squared.sum #=> 146 
p ((1..12) * 6).squared.sum #=> 23400
p ((1..12).squared * 36).sum #=> 23400

https://ideone.com/TMUN29