2011 関数型都市忘年会


    最近書いた
 関数型言語と関連する?
 C++プログラムの紹介
         H.Hiro (Maraigue)
    Web: http://hhiro.net/about/
         Twitter: @h_hiro_
自己紹介




H.Hiro
自己紹介



札幌C++から
 来ました
自己紹介
H.Hiro
• 大学院生(情報系)
• アルゴリズムを考案し、それを実装して
  効果を確かめたりしています(主にC++利用)
• 最近、C++11の機能をいろいろと使いたいが
  ために、研究室のマシンをUbuntuを11に
  アップしました
  (gcc4.5標準搭載のため)
自己紹介
H.Hiro
• 好んで使うもの:C++、Ruby、JavaScript
• 用途次第では使うもの:C#、Python、PHP
• 一応書けるもの:Perl、Java、etc...
自己紹介
H.Hiro
• 好んで使うもの:C++、Ruby、JavaScript
• 用途次第では使うもの:C#、Python、PHP
• 一応書けるもの:Perl、Java、etc...
• まだ使えてないもの:Scala、F#、etc...
自己紹介
•   Twitter: @h_hiro_
•   Facebook: 諸事情により非公開
•   github: maraigue(まれーぐ)
•   ブログ: LivedoorブログのID "maraigue"
•   ニコ動: 探せば見つかります
自己紹介(宣伝)

     数学勉強会@札幌
• 大学数学の内容を取り扱ってます
  (現在は「群論」をやっています)
• 毎週土曜日の10:00~12:00に
  開催
  ※今週については
   日曜10:00~12:00
• 公式サイト:ぐぐって!
自己紹介(宣伝)

   交通勉強会(trafficonf)
• 主に首都圏のメンバーがやっている
  勉強会ですが、私も乗っかってます
  (10/8 札幌でust観覧会を実施)
• 不定期開催(2~3ヶ月に1回)
• 次の開催は1/7
• 次の札幌開催は3/17?
• 公式サイト:
  「交通勉強会準備会」でぐぐって!
最近書いた
関数型言語と関連する?
C++プログラムの紹介
      H.Hiro (Maraigue)
 Web: http://hhiro.net/about/
      Twitter: @h_hiro_
おことわり

別に、直接 "関数型言語" 的な
ことをするわけではないです
おことわり

 別に、直接 "関数型言語" 的な
 ことをするわけではないです
※C++で、「直接 "関数型言語" 的なことを
  する」例:
Boost.勉強会 #6 札幌のuskz氏の発表
http://sites.google.com/site/boostjp/study_meeting/study6
最近書いた
関数型言語と関連する?
C++プログラムの紹介
      H.Hiro (Maraigue)
 Web: http://hhiro.net/about/
      Twitter: @h_hiro_
例題
与えられた文字列に対し、
「どの単語が何番目にあるか」を示す
連想配列を生成したい。
例えば
const std::string text = "I love C++";
という文字列があったとき、連想配列dataを
data["I"] == 0;
data["love"] == 1;
data["C++"] == 2;
となるようにしたい。
回答例(1)
void position(const std::string & str,
              std::map<std::string, size_t> & result){
  size_t number = 0, begin_pos = 0, end_pos;
  result.clear();

    for(;;){
      end_pos = str.find(' ', begin_pos);
      if(end_pos == std::string::npos){
        result[str.substr(begin_pos)] = number;
        break;
      }else{
        result[str.substr(begin_pos, end_pos - begin_pos)] = number;
      }

        begin_pos = end_pos + 1;
        number++;
    }
}
回答例(1)
void position(const std::string & str,
              std::map<std::string, size_t> & result){
  size_t number = 0, begin_pos = 0, end_pos;
  result.clear();

    for(;;){
      end_pos = str.find(' ', begin_pos); // スペースの位置を発見して
      if(end_pos == std::string::npos){
        result[str.substr(begin_pos)] = number;
        break;
      }else{
        result[str.substr(begin_pos, end_pos - begin_pos)] = number;
      }

        begin_pos = end_pos + 1;
        number++;
    }
}
回答例(1)
void position(const std::string & str,
              std::map<std::string, size_t> & result){
  size_t number = 0, begin_pos = 0, end_pos;
  result.clear();

    for(;;){
      end_pos = str.find(' ', begin_pos); // スペースの位置を発見して
      if(end_pos == std::string::npos){
        result[str.substr(begin_pos)] = number;
        break;
      }else{
        result[str.substr(begin_pos, end_pos - begin_pos)] = number;
      } // ↑その部分までの部分文字列をキーとし連想配列に渡す

        begin_pos = end_pos + 1;
        number++;
    }
}
回答例(1)
void position(const std::string & str,
              std::map<std::string, size_t> & result){
  size_t number = 0, begin_pos = 0, end_pos;
  result.clear();

    for(;;){
      end_pos = str.find(' ', begin_pos); // スペースの位置を発見して
      if(end_pos == std::string::npos){
        result[str.substr(begin_pos)] = number;
        break;
                                                 !!!???
      }else{
        result[str.substr(begin_pos, end_pos - begin_pos)] = number;
      } // ↑その部分までの部分文字列をキーとし連想配列に渡す

        begin_pos = end_pos + 1;
        number++;
    }
}
回答例(1)
void position(const std::string & str,
              std::map<std::string, size_t> & result){
  size_t number = 0, begin_pos = 0, end_pos;
  result.clear();
                           関数型な方にとっては
                            普通なことなのかも
    for(;;){
      end_pos = str.find(' ', begin_pos); // スペースの位置を発見して
      if(end_pos == std::string::npos){

                             しれないけど
        result[str.substr(begin_pos)] = number;
        break;
      }else{
        result[str.substr(begin_pos, end_pos - begin_pos)] = number;
      } // ↑その部分までの部分文字列をキーとし連想配列に渡す

        begin_pos = end_pos + 1;
        number++;
    }
}
回答例(1)
void position(const std::string & str,
              std::map<std::string, size_t> & result){
  size_t number = 0, begin_pos = 0, end_pos;
  result.clear();
                           文字列インスタンスを
                            別途生成するとか
    for(;;){
      end_pos = str.find(' ', begin_pos); // スペースの位置を発見して
      if(end_pos == std::string::npos){

                          (C++的には)言語道断!
        result[str.substr(begin_pos)] = number;
        break;
      }else{
        result[str.substr(begin_pos, end_pos - begin_pos)] = number;
      } // ↑その部分までの部分文字列をキーとし連想配列に渡す

        begin_pos = end_pos + 1;
        number++;
    }
}
ポイント
関数型言語では、メモリや速度よりも
処理の実現方法を気にする傾向がある。
ポイント
関数型言語では、メモリや速度よりも
処理の実現方法を気にする傾向がある。
(個人的な印象)
ポイント
関数型言語では、メモリや速度よりも
処理の実現方法を気にする傾向がある。
(個人的な印象)
(例:変数への再代入を避ける)
ポイント
関数型言語では、メモリや速度よりも
処理の実現方法を気にする傾向がある。
(個人的な印象)

でも、メモリを重視しなければ
C++の美学に反する。(個人的な印象)
ポイント
関数型言語では、メモリや速度よりも
処理の実現方法を気にする傾向がある。
(個人的な印象)

でも、メモリを重視しなければ
C++の美学に反する。(個人的な印象)

メモリを節約しつつ、関数型言語くらいの
レベルで記法を簡略化したい
回答例(2)
Boost::splitを使う
(参考URL http://www.gesource.jp/weblog/?p=4531)
void position(const std::string & str,
              std::map<std::string, size_t> & result){
  std::list<std::string> splited;
  boost::split(splited, str, boost::is_space());

    size_t number = 1;
    BOOST_FOREACH(std::string tmp, splited){
      result[tmp] = number;
    }
}
回答例(2)
Boost::splitを使う
(参考URL http://www.gesource.jp/weblog/?p=4531)
void position(const std::string & str,
              std::map<std::string, size_t> & result){
  std::list<std::string> splited;
  boost::split(splited, str, boost::is_space());

    size_t number = 1;

                      記述は分かりやすいけど
    BOOST_FOREACH(std::string tmp, splited){
      result[tmp] = number;


                      でも文字列インスタンスを
    }
}


                       別途生成してるだろ!
つまりは
• すでに存在する文字列(constであることを
  仮定してよい)の部分文字列を
  1つの文字列として扱いたい
 ("I love C++" から "love" や "C++" を得たい)
• ただし、その「部分文字列」インスタンスを
  作る際、文字列をコピーしてはならない
• でも楽に書きたい
 (substrが使えれば楽に書けるんだけど…)
…という状況が私の手元で発生したので
ライブラリを書いたのです。
そのライブラリの名は
そのライブラリの名は




http://www.flickr.com/photos/m-louis/3391434507/
        Creative Commons 2.0 Attribution-ShareAlike
そのライブラリの名は




    fundoshi
http://www.flickr.com/photos/m-louis/3391434507/
        Creative Commons 2.0 Attribution-ShareAlike
そのライブラリの名は




    fundoshi
  (「他人のふんどしで相撲を取る」
    より)
http://www.flickr.com/photos/m-louis/3391434507/
        Creative Commons 2.0 Attribution-ShareAlike
fundoshiについて
gist.githubにあります
https://gist.github.com/1372506
(「fundoshi C++」でぐぐっても出ます)

以下のコマンドで入手可能です
git clone git://gist.github.com/1372506.git
回答例(1)
void position(const std::string & str,
              std::map<std::string, size_t> & result){
  size_t number = 0, begin_pos = 0, end_pos;
  result.clear();

    for(;;){
      end_pos = str.find(' ', begin_pos);
      if(end_pos == std::string::npos){
        result[str.substr(begin_pos)] = number;
        break;
      }else{
        result[str.substr(begin_pos, end_pos - begin_pos)] = number;
      }

        begin_pos = end_pos + 1;
        number++;
    }
}
回答例(3)
void position(const std::string & str,
              std::map<fundoshi::string, size_t> & result){
  size_t number = 0, begin_pos = 0, end_pos;
  result.clear();

    for(;;){
      end_pos = str.find(' ', begin_pos);
      if(end_pos == std::string::npos){
        result[fundoshi::string(&(str[begin_pos]))] = number;
        break;
      }else{
        result[fundoshi::string(&(str[begin_pos]),
               end_pos - begin_pos)] = number;
      }
      begin_pos = end_pos + 1;
      number++;
    }
}
実行例
int main(void){
  std::map<fundoshi::string, size_t> result;
  position("I love C++", result);

    std::cout << result["I"] << std::endl;
    std::cout << result["C++"] << std::endl;
    std::cout << result["love"] << std::endl;
}
実行例
int main(void){
  std::map<fundoshi::string, size_t> result;
  position("I love C++", result);

    std::cout << result["I"] << std::endl;
    std::cout << result["C++"] << std::endl;
    std::cout << result["love"] << std::endl;
}
↓
0
2              きたこれ!
1
簡単なリファレンス(1)
• クラス名
  – template <class CharType>
    fundoshi::basic_string<CharType>;
  – typedef basic_string<char> string;
  – typedef basic_string<wchar_t> wstring;


※std::stringとかに名前を合わせてます
 メソッド名も基本的には合わせてます
簡単なリファレンス(2)
• コンストラクタ
 – basic_string();
   // 空文字列
 – basic_string(const CharType * newstr, size_t length);
   // 文字列の一部を切り出す場合
 – basic_string(const CharType * newstr);
   // '¥0'終端の文字列を使う場合
 – basic_string(
     const std::basic_string<CharType> & newstr);
   // std::basic_string (std::stringなどを含む) を使う場合
簡単なリファレンス(3)
• ポインタを貰う
 const CharType * c_str(void) const;
• 長さを取得
 size_t length(void) const;
• 文字を取り出す
 CharType operator [](size_t pos) const;
• 文字列比較
 bool operator ==(const basic_string<CharType> & other) const;
 bool operator < (const basic_string<CharType> & other) const;
 bool operator <=(const basic_string<CharType> & other) const;
 bool operator > (const basic_string<CharType> & other) const;
 bool operator >=(const basic_string<CharType> & other) const;
おことわり


   APIは
(今のところ)これで
  全部です!
おわりに
• 私はよくRubyも使ってるのだが
  Rubyに慣れてしまうと
  C++って記法がエレガントじゃないよね
• だから記法にこだわっている
• boostとかその点頑張ってるっぽいので
  タイミングを見て勉強してみたいです
おわりに


   (再掲)
  関数型言語
あまり関係なかった。
 本当申し訳ない。
おわりに


 (もし時間が余ったら)
もう一つ「記法にこだわる」
    ネタをします
おわりに



 ありがとう
ございました

2011.12.10 関数型都市忘年会 発表資料「最近書いた、関数型言語と関連する?C++プログラムの紹介」