2016/4/16 ちゅーん(@its_out_of_tune)
HN: ちゅーん
Twitter:
@its_out_of_tune
Github:
tokiwoousaka
あと東京から引っ越して来て某社に入社しました
インパクトがあれば何でも良いかなって
反省はしていない
一言二事言いたい事はあるものの
言うほど酷く無かった
我々が「欲しい」と考える
OOPLの機能を得るための
「Haskellらしい」仕組みの紹介
@fumievalさんによる
Haskell上でOOPを実現するための道具立て
https://hackage.haskell.org/package/objective
CabalなりStackなりで
良い感じにインストールして使おう
サンプルとしてカウンターを作ろう
まずGADTs言語拡張を用いてインターフェイスを定義。
data Counter a where
PrintCount :: Counter ()
Increment :: Counter ()
インターフェイスを実装する
(@~)演算子の左辺に状態の初期値を与える。
右辺は StateT s IO モナドで各メソッドを実装。
counter :: Int -> Object Counter IO
counter i = i @~ \case
PrintCount -> get >>= liftIO . print
Increment -> modify (+1)
new関数でインスタンス作成
(.-)演算子でメソッド呼び出し
main :: IO ()
main = do
cntr <- new $ counter 10
cntr.-PrintCount -- 10が出力される
cntr.-Increment
cntr.-Increment
cntr.-Increment
cntr.-Increment
cntr.-PrintCount -- 14が出力される
objectiveにももちろん
既存のオブジェクトを拡張するための
便利な機能が備わっています。
その前にobjectiveの型の読み方を説明しておこう
便宜上「インターフェイス」「メソッド」を使ったが
objectiveの基礎的な考え方はメッセージパッシングだ
-- 次のように送受信メッセージを型引数として取る
Object [受信メッセージ] [送信メッセージ]
-- インスタンスを使うにはIOを送信しなくてはいけない
new :: Object f IO -> m (Instance f IO)
(.-) :: Instance f IO -> f a -> IO a
【縦の合成】
左辺のオブジェクトの受信メッセージを受け
右辺のオブジェクトの送信メッセージを送る
新しいオブジェクトを作成する。
(@>>@) :: Functor h => Object f g -> Object g h -> Object f h
【横の合成】
左辺のオブジェクトの受信メッセージと
右辺のオブジェクトの受信メッセージを纏め上げた
新しいオブジェクトを作成する。
data Sum f g a = InL (f a) | InR (g a)
(@||@) :: Functor m => Object f m -> Object g m -> Object (Sum f g) m
二つの合成については、
次のように解釈すると分かりやすい
上手く組み合わせれば、
継承と概ね同等の拡張を実現出来る
実際使いこなすにはOperationalとか
もう少し高度な知見も必要ですが……
「数学」という言葉を使うとまた荒れそうなので
「形式的」という言葉に言い換えます
ここでいう「形式的」は
「厳密な定義の組み合わせで曖昧性/矛盾なく説明できる」
くらいの意味です
①何か型をつくる
②Monadクラスのインスタンスにする
③ちゃんとモナド則を満たす事を確認する
④その型は例外なくモナドです
こう言い切ってしまえば、
「モナドとは何か」なんて議論する余地は、
本来無いはずなのですよっ(`・ω・´)
たぶん
①メッセージの送受信
メッセージを関手として、自然変換が相当する
nat :: m a -> n a
--自然変換は自然性という性質を満たす
nat . fmap f == fmap f . nat
②状態を持つ
ミーリ・マシン:入力aを受けると出力bを返し、
自身の状態を書き換えるオートマトンの一種。
newtype Mealy a b = Mealy
{ runMealy :: a -> (b, Mealy a b) }
オブジェクトはミーリ・マシンの性質を持った
ただの自然変換だよ?何か問題でも?
---- Natural ----
forall x. f x -> g x
---- Mealy ----
newtype Mealy a b
= Mealy { runMealy :: a -> (b, Mealy a b) }
---- Object ----
newtype Object f g
= Object { runObject :: forall x. f x -> g (x, Object f g) }
対象について形式的に述べる事によって
それが何なのか明瞭になるばかりでは無く
その対象の持つ性質を遺憾なく発揮した
高度なプログラミングを実現出来る!
おまけ:
縦合成は単位元としてechoという
特殊なオブジェクトを持ち、結合則を満たします。
つまり、メッセージを対象としてオブジェクトを射とした、
「オブジェクトの圏」を定義できます。
嬉しい✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌
開発者@fumievalさん曰く
オブジェクトは現実的な問題を解決するには
強すぎる道具立てである、従って……
「ゲームとかGUIくらいしか無いと思います」
もっと軽いシチュエーションでも
使い所あるんじゃ無いかなぁ……例えば……
ちょっとしたツール作る時とかに。
適切に使わないと死ぬかもしれない