Haskellの実験メモです。
ECMAScript 6のジェネレーターでHaskellのリストモナドを模倣してみました。
一重
Haskell
main = do
print $ do
x <- [1..5]
return $ x * 2
実行結果
[2,4,6,8,10]
これになるべく近くなるように模倣してみました。ジェネレーターやfor
~of
は動作環境を選びます。
ES2015
console.log(Array.from(function*() {
for (let x of [1, 2, 3, 4, 5]) {
yield x * 2;
}
}()));
実行結果
[ 2, 4, 6, 8, 10 ]
参考までに、ジェネレーターを使わない例を示します。
ES2015
console.log(function() {
let ret = [];
for (let x of [1, 2, 3, 4, 5]) {
ret.push(x * 2);
}
return ret;
}());
実行結果
[ 2, 4, 6, 8, 10 ]
この方式は以下の記事で使用しています。
- Haskell リストモナド 超入門 2014.12.19
二重
Haskell
main = do
print $ do
x <- [1..3]
y <- "abc"
return (x, y)
実行結果
[(1,'a'),(1,'b'),(1,'c'),(2,'a'),(2,'b'),(2,'c'),(3,'a'),(3,'b'),(3,'c')]
同じ方針で模倣します。
ES2015
console.log(Array.from(function*() {
for (let x of [1, 2, 3]) {
for (let y of "abc") {
yield [x, y];
}
}
}()));
実行結果
[ [ 1, 'a' ],
[ 1, 'b' ],
[ 1, 'c' ],
[ 2, 'a' ],
[ 2, 'b' ],
[ 2, 'c' ],
[ 3, 'a' ],
[ 3, 'b' ],
[ 3, 'c' ] ]
タプルがないため配列で代用しています。
フラット化
Haskellではreturn
ではなく複数の項目を含むリストを返すとフラット化されます。LINQのSelectMany
やScalaのflatMap
と関係があります。
タプルと比較します。リストにする関係上、要素の型は同じにします。
Haskell
main = do
print $ do
x <- [1,2]
y <- [3,4]
return (x, y)
print $ do
x <- [1,2]
y <- [3,4]
[x, y]
実行結果
[(1,3),(1,4),(2,3),(2,4)]
[1,3,1,4,2,3,2,4]
join
とreturn
を省略しているとも解釈できます。リスト内包表記で結果をフラットにするにはjoin
必須です。
Haskell
import Control.Monad
main = do
print $ do
x <- [1,2]
y <- [3,4]
return [x, y]
print [[x, y] | x <- [1,2], y <- [3,4]]
print $ join $ do
x <- [1,2]
y <- [3,4]
return [x, y]
print $ join $ [[x, y] | x <- [1,2], y <- [3,4]]
実行結果
[[1,3],[1,4],[2,3],[2,4]]
[[1,3],[1,4],[2,3],[2,4]]
[1,3,1,4,2,3,2,4]
[1,3,1,4,2,3,2,4]
ジェネレーターで模倣するにはyield
を複数回に分けるのが簡単です。
ES2015
console.log(Array.from(function*() {
for (let x of [1, 2]) {
for (let y of [3, 4]) {
yield x;
yield y;
}
}
}()));
実行結果
[ 1, 3, 1, 4, 2, 3, 2, 4 ]
関連記事