Skip to content

Instantly share code, notes, and snippets.

@as-capabl
Created May 10, 2019 03:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save as-capabl/aac1737c141f1d62c6652387d461cef9 to your computer and use it in GitHub Desktop.
Save as-capabl/aac1737c141f1d62c6652387d461cef9 to your computer and use it in GitHub Desktop.
妄想C++言語拡張 - オーバーロード可能セミコロンとしてのモナド

言語拡張は以下の2点。

  • クラスにoperator doを定義できるようにする
  • do 型名 { 変数宣言 <- 値; 値; ...} という構文の新設

使用イメージは以下のような感じ。

// モナドの型
template <typename T> class MyMonad {
  MyMonad(const T& t) {...} // Haskellのpure(return)に相当

  ...

  template <typename R, typename F>
  MyMonad<R> operator do (F f) {...}
  // Fは `function< MyMonad<R> (const T&) >` 。
  // Haskellに翻訳すると `(>>=) :: MyMonad T -> (T -> MyMonad R) -> MyMonad R`
  // ただし第一引数はthisで与える。
};

// プリミティブコマンド
MyMonad<int> command(int n) {...}


main () {
  // モナドの実体の記述
  auto m = do MyMonad {
    auto x <- command(10);
    command(x);
    return x;
  }
  ...
}

これは

main() {
  auto m = MyMonad<unit_type>( unit_type() ).operator do(
    [](unit_type) {
      command(10).operator do(
        [](auto x) {
          return command(x).operator do(
            [](auto) {
              return MyMonad<decltype(x)>(x);
            }
          )
        }
      )
    }
  );
  ...
}

に脱糖される。後続の式が [] {} の中に入れられてoperator do (...) { operator do(...) {...} } の入れ子に変換されるイメージ。

ここで struct unit_type {}; は標準で提供する型。Haskellの()に相当。 本来C++で f :: IO () に相当するのは void f() だが、MyMonadの扱いが煩雑なのでこのようにした。

command(10).operator do から始まっても良いのだが、commandに副作用があった場合に 1行目のみ即座に実行されてしまうという非直感的な動作になる。 そこで、先頭に pure () があるものとして脱糖している。モナド則から pure () >> x === x

return文が無かった場合 return MyMonad(unit_type); が最後にあるものとして脱糖する。

変数宣言 = 値; ではなく 変数宣言 <- 値; としたのは…… int x = MyMonad<int>(10); みたいに左右の型が合わないのはキモいよねっていう。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment