このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

TypeScriptのモジュール:Maybeモナドの例

TypeScriptと関手やモナドなど」:

型構成子と型パラメータを持つ関数があれば、とりあえずモナドは定義できるのですが、モナドを構成する型構成子と総称関数達をうまくまとめる機構が欠けている感じはします。

TypeScriptの「まとめる機構」にモジュール(module)ってのがありますね。モジュールで、型や関数をまとめてグループにできます。Maybeモナドを例題にして、モナドの構成要素にまとまりをつけてみます。

なお、Maybeモナドの概念的なことは「アイレンベルグ/ムーア圏 その3:Maybeモナドのとき」に割と詳しく書いてあります。そこで使われている名前は、fmap, just, flatten ではなくて lift, embed, join ですのでご注意。

// Maybeモナド
module Maybe {
  // 型構成子:関手の対象部分
  export 
  class Data<X> {
    private _hasVal: boolean;
    private _val: X;

    constructor(hasVal:boolean, val?:X) {
      this._hasVal = hasVal;
      this._val = val;
    }
  
    get hasVal() {return this._hasVal;}
    get val() {return this._val;}
  }

  // 定数:値がないことを表すオブジェクト
  export
  const None = new Data<any>(false);

  // マップ関数:関手の射部分
  export
  function fmap<X, Y>(f:(x:X)=>Y) : (mx:Data<X>)=>Data<Y> {
    return (
      (mx:Data<X>)=> (!mx.hasVal)? <Data<Y>>None : new Data<Y>(true, f(mx.val))
    );
  }
  // モナド単位
  export
  function just<X>(x:X) : Data<X> {
    return new Data<X>(true, x);
  }
  // モナド乗法
  export
  function flatten<X>(mmx:Data<Data<X>>) : Data<X>{
    return (
      (!mmx.hasVal)? <Data<X>>None : mmx.val
    );
      
  }
}

次のように使います。

// Maybeデータの生成: just true
var mt: Maybe.Data<boolean> = Maybe.just(true);
// Maybeデータの操作: not で否定
var mf: Maybe.Data<boolean> = Maybe.fmap((t:boolean)=> !t)(mt);
// Maybeデータを入れ子にする
var mmf: Maybe.Data<Maybe.Data<boolean>> = Maybe.just(mf);
// 入れ子をほどく
var mf2: Maybe.Data<boolean> = Maybe.flatten(mmf);

目的が共通なモジュールが一律に備えるべき型や関数の仕様(interfaceのモジュール版)を書けると、型クラスみたいに使えるんですけどね。「Maybeモジュールは、Monad仕様のインスタンス」という感じで、具体的モジュールより一段上の抽象化をサポートできます。入らないかな、そんな機能。