色々な言語で偶数自乗和

TL;DR

このごろ新しく言語を見る時、Hello world の次くらいに偶数自乗和を 作る関数を定義してる。Ruby で書くとこんな感じ。

def even_square_sum(n)
    (1..n)
        .select {|n| n % 2 == 0} 
        .map {|n| n * n} 
        .inject {|acc, n| n + acc}
end
puts(even_square_sum(10)) # => 220 が表示されると正解

いくつかルールがあって

  • リストの内包表記は使わない
  • range 的なのがあれば使う
  • 最後の合計はなるべく畳み込み(reduce, fold系) を使う

これをやると

  • 無名関数の定義のしかた
  • 関数の定義のしかた
  • 関数の呼び出しかた
  • 基本的な高階関数の使い方

が分かるので、なかなか気にいってる。 では今まで作ったのを紹介してみる。

Rust

fn even_square_sum(n: isize) -> isize {
    (1..n)
        .filter(|n| n % 2 == 0)
        .map(|n| n * n)
        .fold(0, |acc, x| acc + x)
}

fn main() {
    let result = even_square_sum(10);
    println!("{}", result);
}

普通かな。 でもこの書き方をゼロコストでやってくれるのはいいね。

Common Lisp

(defun range (from to &optional (res '()))
    (if (eq from to) (cons to res)
        (range from (1- to) (cons to res))))

(defun even-square-sum (n)
    (reduce #'+
        (mapcar #'(lambda (n) (* n n))
            (remove-if-not #'evenp (range 1 n)))))

(setq result (even-square-sum 10))
(print result)

range がなかったので自作してみた。末尾再帰ではないので、ヒマがあったら変えたい。 適用する順番が頭で考えるのと逆順になってしまうので読みづらい。 マクロ作ればパイプライン的な事もやれそうだけど。

TypeScript

function evenSquareSum(n: number): number {
    const numList: number[] = Array.from(Array(n).keys());
    return numList
        .filter((n) => n % 2 == 0)
        .map((n) => n * n)
        .reduce((acc, n) => acc + n);
}
const result = evenSquareSum(10)
console.log(result);

普通かな。range がないので、Array.from() を使ったけどやはり気持ち悪い。

Elixir

evenSquareSum = fn (n) ->
    (1..n)
        |> Enum.filter(fn n -> rem(n, 2) == 0 end)
        |> Enum.map(fn x -> n * n end)
        |> Enum.reduce(0, fn n, acc -> n + acc end)
end
result = evenSquareSum(10)
IO.puts(result)

パイプライン演算子(|>)いいね。 リスト操作以外にも使えそうだし、 もっと他の言語にも取り入れてもらいたい。

import Enum
1..10 |> filter(&rem(&1, 2) == 0) |> map(&(&1 * &1)) |> reduce(&(&1 + &2))