LoginSignup
1
0

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-01-01

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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0