t/o
解説
Squeak Smalltalk やその派生である Pharo には APLっぽい配列演算が組み込みの機構として用意されています。
(6 + (1 to: 12)) squared sum "=> 2018 "
ちなみに本家の APL では同じことを次のように書くことができます。
+/(6+⍳12)*2
念のため ⍳(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 "
これが、クイズを解くのに参考になるようなならないようなヒントです。
なお、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 も別途定義が必要です。
もとより、ケント・ベックの仮実装ばりに酷いコードですので、あとの改良はお任せします。^^;
追記:もう少しまともにした版
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