汎用的なaccumulateが書けない言語使いで許されるのは小学生まで。


本日も楽しい楽しいSICP読書会に行ってきました。

 高階手続きを使ったsum→product→accumulate→filtered-accumulateの流れは余りに美味しくて、これをつまみに日本酒一升くらいは空けられそうです

この、Don't Repeat Yourselfを体現する話の流れは官能的に美しいわけです。
そんで、やっぱり汎用的なaccumulateが書けないようなプログラミング言語(例えばJava)は、script kiddyが使うにはいいとしても大人が使う言語じゃないだろうと思うわけです。

C++のような変態言語だって書けるのに。あと、なんというか思うわけですが、Javaってせめて型推論でもつけてくれないと使い物にならなくね?

C++版accumulateの実行はこちらで。
http://codepad.org/A23rW5pA

#include<iostream>
#include<list>
#include<string>

using namespace std;

template<typename T>
T add(const T& lhs, const T& rhs){
	return lhs + rhs;
}
template<typename T>
T mul(const T& lhs, const T& rhs){
	return lhs * rhs;
}

template<typename T>
T accumulate(T (*comb)(const T&, const T&), const T& initial, list<T>& ls){
	T ret(initial);
	typedef typename list<T>::iterator Iterator;
	for( Iterator i=ls.begin(); i!=ls.end(); i++ ){
		ret = comb(ret, *i);
	}
	return ret;
}

int main(){
	list<int> ls;
	for( int i=0; i<10; i++){
		ls.push_back(i+1);
	}
	cout << accumulate(add, 0, ls) << endl;
	cout << accumulate(mul, 1, ls) << endl;

	list<string> ls2;
	ls2.push_back("a");
	ls2.push_back("b");
	ls2.push_back("c");
	ls2.push_back("d");
	ls2.push_back("e");
	string empty("");
	cout << accumulate(add, empty, ls2) << endl;
	return 0;
}

他の言語版accumulate

JavaScript

function accumulate(func, initial, ls){
  var ret = initial;
  for( var i=0, len=ls.length; i<len; i++ ){
    ret = func(ret, ls[i]);
  }
  return ret;
}
accumulate(function(x, y){ return x + y; }, 0, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
accumulate(function(x, y){ return x + y; }, "", ["a", "b", "c"]);

python
http://codepad.org/npr7BfQ6

# -*- coding: utf-8 -*-
#自分で書く必要はない
print reduce(lambda x, y: x + y, range(1, 11))
print reduce(lambda x, y: x + y, ["a", "b", "c"])

ruby
http://codepad.org/xFRWOlIB

#自分で書く必要はない
p (1..10).inject(0){|a, b| a + b}
p ["a", "b", "c"].inject(""){|a, b| a + b}

perl
http://codepad.org/DJIaHY2M

#自分で書く必要はない
use strict;
use List::Util qw/reduce/;
print reduce { $a + $b } (1 .. 10);
print reduce { $a . $b } ("a", "b", "c");

PHP



本当にありがとうございました。

PHP版のaccumulate

PHPのcreate_functionの仕様がなんか好きじゃないから、夜遅かったし面倒くさかったしオチにちょうどよかったから途中でやめたんですが、


PHPを貶めようとしている危険なエントリ。
なんか怒られたのでPHP版も書くとこうですかね?

http://codepad.org/BXWMhVAl

<?php
echo array_reduce(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), create_function('$a,$b', 'return $a+$b;'));
echo array_reduce(array("a", "b", "c"), create_function('$a,$b', 'return $a.$b;'));
?>

C++には標準でaccumulateありました。ごめんなさい。

コメント欄で教えてもらいましたが、C++も自分で書く必要はなかったようです。さすがは変態言語。

http://codepad.org/IhxArZGN

#include<vector>
#include<list>
#include<string>
#include<iostream>
#include<numeric>        //accumulate
#include<functional>    //multipliesなど

using namespace std;

int main(){
	//iterator渡しなのでvectorでもおk
	vector<int> vec(10);
	for( int i=0; i<10; i++ ){
		vec[i] = i+1;
	}
	//デフォルトでは加算
	cout << accumulate(vec.begin(), vec.end(), 0) << endl;

	//multipliesとかも渡せる。
	list<int> ls;
	for( int i=0; i<5; i++ ){
		ls.push_back(i+1);
	}
	cout << accumulate(ls.begin(), ls.end(), 1, multiplies<int>()) << endl;

	//iterator渡しということは、ポインタ渡してもおkwwww
	string array[] = { "a", "b", "c" };
	string empty("");
	cout << accumulate(array, array+3, empty) << endl;
	return 0;
}

accumulate祭 Java版

どうかと思うコードだけど、効率は度外視すれば、オートボクシングとGENERICSを駆使してできないことはないようです。

abstract class Combiner<T> {
  public abstract T apply(T lhs, T rhs);
}

public class Hoge {
  public static <T> T accumulate(Combiner<T> comb, T initial, Iterable<T> array){
    T ret = initial;
    for( T i : array ){
      ret = comb.apply(ret, i);
    }
    return ret;
  }
  public static <T> T accumulate(Combiner<T> comb, T initial, T[] array){
    return accumulate(comb, initial, java.util.Arrays.asList(array));
  }

  public static void main(String[] args){
    Number[] i_array = {1, 2, 3};
    Combiner<Number> i_add = new Combiner<Number>(){
      public Number apply(Number lhs, Number rhs){
        return new Integer(lhs.intValue() + rhs.intValue());
      }
    };
    p(accumulate(i_add, 0, i_array));

    Number[] d_array = { 3.14, 2.7182818284 };
    Combiner<Number> d_mul = new Combiner<Number>(){
      public Number apply(Number lhs, Number rhs){
        return new Double(lhs.doubleValue() * rhs.doubleValue());
      }
    };
    p(accumulate(d_mul, 1, d_array));

    Combiner<String> s_add = new Combiner<String>(){
      public String apply(String lhs, String rhs){
        return lhs + rhs;
      }
    };
    String[] s_array = { "a", "b", "c" };
    p(accumulate(s_add, "", s_array));
  }
  public static void p(Object o){
    System.out.println(o);
  }
}