8. みんなだいすきリスト内包
単純に map, filter の別表現として
[ x * x | x <- xs, odd x ]
-- リスト xs のうち奇数の要素を抽出してさらに2乗
生成部を複数もつことができ、組み合わせを展開できる
[ (x, y) | x <- xs, y <- ys, x /= y]
-- リスト xs, ys の要素のすべての組み合わせのうち
-- 同じ要素でないもの
Pythonのリスト内包も負けないくらい強力!(ステマ)
[(x, y) for x in xs for y in ys if x != y]
9. リスト内包のひみつ
[ (x, bar) | (x,y) <- foos, x < 2,
bar <- bars, bar < y ]
等価
foos >>= (x, y) -> guard (x < 2) >>
bars >>= bar -> guard (bar < y) >>
return (x, bar)
http://en.wikibooks.org/wiki/Haskell/Syntactic_sugar
17. リストのreturn
Haskell
return :: Monad m => a -> m a
return x = [x]
JavaScript
A.mreturn = function(x) { return [x]; };
// クラスメソッド
A.prototype.mreturn = function(x) { return [x]; };
// インスタンスメソッド
return が予約語なので mreturn という名前で定義
便宜上、クラスとオブジェクト両方に実装
18. リストの>>=
Hakell
(>>=) :: Monad m => m a -> (a -> m b) -> m b
m >>= k = foldr ((++) . k) [] m
ぱっと見で何やってるかわかりづらい
型の m を [ ] に置き換えて、
さらに理解しやすく書きなおすとこう↓
(>>=) :: [a] -> (a -> [b]) -> [b]
xs >>= f = concat $ map f xs
左辺のリスト xs を 関数 f :: a -> [b] で map して得られるリストのリス
トを concat (連結)している
21. ところで >> は?
Haskell
(>>) :: m a -> m b -> m b
m >> k = m >>= _ -> k
右辺が左辺値を使わない状況で >>= の代わりに使える
つまり、
Prelude> [1..3] >>= _ -> [0,1]
[0,1,0,1,0,1]
を、もっと短くこう書ける
Prelude> [1..3] >> [0,1]
[0,1,0,1,0,1]
22. リストの>>=
JavaScript
// (>>=) :: Monad m => m a -> (a -> m b) -> m b
// this >>= f = foldr ((++) . f) [] this
A.prototype.mbind = function(f) {
return this.reduceRight(
function(acc, x) { return f(x).concat(acc); },
[]
);
};
24. MonadPlus って何ぞ?
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
instance MonadPlus [] where
mzero = []
mplus = (++)
…加法?…単位元…?モナドをモノイドみたいに扱うの?
何に使うんだろ(´・ω・`)今は気にしないでおこう(遅延理解)
ともあれ、リストの mzero は空リスト
だということがわかる。
26. guard 関数
というわけで、まずは MonadPlus を実装
JavaScript
// mzero :: MonadPlus m => m a
// mzero = []
A.mzero = [];
// mplus :: MonadPlus m => m a -> m a -> m a
// mplus = (++)
A.prototype.mplus = A.prototype.concat;
40. モナディック関数のあれやこれ
// join :: m (m a) -> m a
// join x = x >>= id
function join(x) { return x.mbind(id); }
// (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
// f (>=>) g = x -> f x >>= g
function mcompose(f, g) {
return function(x) {
return f(x).mbind(g);
};
}
// liftM :: (a1 -> r) -> m a1 -> m r
// liftM f m1 = m1 >>= x1 -> return (f x1)
function liftM(f) {
return function(m1) {
return m1.mbind(function(x1) {
return m1.mreturn(f(x1));
});
};
}
mreturn と mbind しか使ってないので他のモナドでもちゃんと動くよ!