北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

今日は 第5回 スタートHaskell の日です

生憎の雨ですが、大森ベルポートニフティさんに来てます。途中退室の予定ですが、居る間に聞いた内容をメモ。

第10章:クラスとインスタンスの宣言 / @ruicc さん

  • OOからHaskellの型・型クラスの理解をする
  • 型クラスと型インスタンスがOOのクラスである
    • 型クラスはメソッド、型はフィールド
  • 状態 = 大いなるバグの母
  • 直積構造(タプルみたいなもの)、直和構造(orみたいなもの)、再帰構造(リスト、木)
  • data IntOrSome a = MkInt Int | MkA a
    • IntOrSome : 型構成子
    • MkInt, Mka : 値構成子
  • type IntOrStr = IntOrSome String
    • 値構成子がない
  • 直積構造 → OOではフィールド、Haskellでは型構成子
  • 直和 → OOはステートパターンや状態をフラグで管理。Haskellでは | で直接表現
  • 再帰構造 → OOは自分の型をフィールドにもつ(コンポジット、ビジターパターン)。Haskell は書き下せる
  • OOだと意図が
  • Haskellではprivateがない
    • Haskellは状態がないので、そもそも要らない
    • パフォーマンスを改善する場合にはモジュール単位で隠す(where, module単位)
  • OOでは列挙型が欲しくなる → 直和型がないから
  • 継承とはなんだったのか
    • メソッドの、型の継承+実装の継承
    • 型の継承 → フィールド非依存
    • 実装の継承 → フィールド依存
  • Haskellの型クラス同士の継承はフィールド非依存、型はフィールド依存
  • OOはオーバーライドが複数回行われる。Haskellは一回
  • 型クラスは多重継承が可能
  • C++Pythonでも多重継承できる?
    • うまくはできない。マクロやコードジェネレータで差が出る
  • 型クラスはScala のTraitと似てる → Scalarzにそんなのがある
  • class Eq a where (==), (/=) :: a -> a -> Bool
    • 型クラスEq, 型パラメータa、 型クラスのメソッド==, /=
  • instance Eq MyType where x == y = ...
  • クラスの継承 class (Eq a) => Ord a where ...
    • => で指定
  • 特定のクラスのインスタンス化が簡単になるようにしている
    • deriving (Eq, Ord, Show, Read, ...)
    • 仕組みはwww.haskell.org でググって
  • 型クラスは2種類
    • instance Eq (Maybe Int)
    • instance Monad Maybe → 型パラメータを1つとる型の宣言
  • モナドなどに関するヒント
    • Monad, Functor, Applicative
    • 要素はコンテナと中身しかない。
  • 質疑応答
    • 「Q. 10.6のevalとexecって?」
    • 「A. 評価順を明確にするために2つの関数に分けている」
    • 「Q. 型クラスはOOのクラスでなく、総称関数のインタフェースってことでいい? 実装を与えるのがインスタンス?」
    • 「A. はい。クラスって名前は忘れた方がいい。同じ名前の関数を持つグループ。」
    • 「Q. C#Javaのインタフェースと同じ?」
    • 「A. はい。ただしHaskellはデフォルト実装を持てる」
    • Haskellでは、既存のインスタンスを自分のクラスにしたりできる

切符番号選び(11章) / @dekosuke さん

  • Twitterの数字遊び
    • 4つの数字が出て、10にする
    • 演算が決まってない。ルールがあいまいで面白い
  • 切符番号選び
    • 四則演算のみ、好きな数字を選んでよい、0になっては駄目
  • data Op = Add | Sub | Mul | Div → 四則演算
  • valid, apply : 正当かどうか。演算結果はどうか
    • 分けなくてもMaybe でいいんじゃん?
  • data Expr = Val Int | App Op Expr Expr
  • eval : 式を評価。List型だが実質Maybe
  • subs : 冪集合を求める
  • perms : 並び替え
  • choices : perms + subs
  • solution : Exprが答えになっているか調べる (未使用)
  • solutions : 全ての回答を探す
  • combine : 二つの演算に四則演算を総当たりで適用したリスト
  • ops : 四則演算のリスト
  • exprs : 与えた数値を使った式を全て返す
  • このプログラムは遅い(4分かかる)
    • validでない式を落としてない (最後にevalしているため)
  • 高速化
    • type Result = (Expr, Int)
    • combine' : Result へ四則演算を総当たりする
    • results : 数値を使った式を全て作って評価
    • solutions' : 速い版。数十秒。
  • さらに工夫
    • 可換な演算は片方でよい、x×1 は自明なので略す
  • 組み合わせ爆発の時は、小さな工夫も指数的に効く

モナモナ言わないモナド入門 / @kazu_yamamoto さん

  • モナドは名前が悪い。抽象的だからわかりにくい
    • 物理学の統一理論、大統一理論と同じ
    • 状態系(IO, State)、失敗系(List, Maybe)の共通点を見つけ、コンテナを見つける
  • ParserとIOの共通点を探す
    • データ定義が似ている
    • ラップする関数がある
    • 合成する関数がある
    • 抽象化オタクなら抽象化したくなるはず → class Stateful m where swrap, sbind
  • 抽象化すると何が嬉しい? → do記法
  • Stateful の中身は関数なので、走らせなければならない
    • 関数を取り出し、runParserやrunIOする
    • IOは公開されてないため、runIOできない → ランタイムが実行
  • Maybe → 複数回関数適用すると、場合分けが指数関数的に増える
    • 失敗をいい感じで合成する関数 → mbind
  • data List a = Nil | Cons a (List a)
  • MaybeとListを抽象化 → class Failable m where fwrap, fbind
    • searchによって抽象化の恩恵を受ける例
  • Philip Wadler → StatefulとFailableを統一、Programmable
    • Failable でもdo が使える
  • 力の弱いものを使う(再帰よりmap)
  • コンテナの力の階層 強) >>= 、<*>、<$> (弱
  • チューリング完全
    • 構造化定理 : 逐次、分岐、反復
    • Mappable (<$> (fmap))
    • <*> (ap)
    • 心眼で<$>と<*>を消すと、(+) (Just 1) (Just 2) に見える
  • <*>はdoを書き換えられるので、逐次。再帰しているので反復もできる
    • >>= が分岐を表現する
  • なぜモナド? → モナドチューリング完全だから
  • モナドの嬉しさ
    • do、差し替え可能な文脈、差し替え可能な実装、モナド変換子
  • IOモナドとかMaybeモナドとか、「モナド」とつけて呼ぶのは犯罪
    • IOもMaybeも特別なものでない
    • 糖衣構文 do がモナドを特殊にしている
  • 本来はFunctor → Applicative → Monad だけど、そうなってない
  • 内包表記は、doの別表記
    • scalar のfor も同じ
    • 1990年にでき、1997年にモナド内包表記へ一般化されたが、1999年に戻された
    • モナド内包表記 のエラーメッセージがわかりにくかった(糖衣構文のため)
    • また戻った(SQLも表現できるっぽい)
  • 表記
    • Parser はApplicative
    • IO はdo
    • Maybe は>>=
    • List は内包表記
  • 質疑応答
    • Q. Functor, Applicative, Monad の力の強弱
    • A. FunctorとApplicativeは似たようなもの。Monadは分岐
    • Q. typeは合うけど、monadが限定されるということはあるのか
    • A. forM_ とかはIO を期待している
  • Applicativeの良さ
    • data KV = KV String Int でパーサを書くとき、持ち上げができる


ここで退室しました。関係者のみなさん、おつかれさまでした!