##追記
未だにアクセスしてくださるかたが多いのに、 古いし、JS力がなくて申しわけない。
JSの部分だけ、今だとこんなかな?というのを追記します。
const predMax = xs => {
const [ws, [y, ...ys] ] = breakBy( Math.max(...xs) )(xs)
return [...ws, y - 1, ...ys]
}
const breakBy = a => xs =>{
const i = xs.indexOf(a)
return [ xs.slice(0, i), xs.slice(i)]
}
const iterGen = f => xs => function*(){
let a = xs
while (true){
yield a = f(a)
}
}()
const a = iterGen(predMax)([10,8,6])
for (const _ of Array(10)){
console.log(a.next().value)
}
以下、元記事
関数型プログラミングはまず考え方から理解しようを読んで、勉強になったし、自分でもやってみたのでメモ。のつづき。
唐揚げつまんでみたでいろいろ教えていただいて、最終的にはこんな風になりました。
Haskell:
predMax xs = ws ++ pred y : ys
where
(ws, y:ys) = break (== maximum xs ) xs
main = print $ take 10 $ tail $ iterate predMax [10,8,6]
JavaScript:
(function() {
// window.onload = function(){
iterate = function(f,xs,n){
if(n === 1) return [f(xs)];
return [f(xs)].concat(iterate(f, f(xs), n - 1 ));
};
predMax = function(xs) {
var indexMax = xs.indexOf( Math.max.apply( null, xs ) );
return xs.slice(0, indexMax ).concat(
[xs.slice(indexMax, indexMax + 1 )[0] - 1 ]
, xs.slice(indexMax + 1, xs.length )
);
}
console.log(iterate(predMax, [ 10, 8, 6 ], 10 ));
// }
}())
JSの方もHaskellと似たようなことをしています。
だいたいこれで自分としては満足なのですが、
#まてよ、俺は別にインデックスを知りたいわけではなかったな
、とか思いはじめ、もうちょっとだけHaskellによるように手を入れてみました。
(function() {
// window.onload = function(){
iterate = function(f,xs,n){
if(n === 0) return [f(xs)];
return [f(xs)].concat(iterate(f, f(xs), n - 1 ));
};
tail = function(xs) {return xs.slice(1);};
head = function(xs) {return xs[0]};
maximum = function(xs) {return Math.max.apply( null, xs )};
breakBy = function(a,xs) {
return [ xs.slice(0,xs.indexOf(a)), xs.slice(xs.indexOf(a)) ] ;
};
pred = function(x) {return x - 1 };
fst = function(xs) {return xs[0] };
snd = function(xs) {return xs[1] };
predMax = function(xs) {
var breakByMax = breakBy(maximum(xs), xs);
return fst(breakByMax).concat(
[ pred( head( snd( breakByMax ))) ]
, tail( snd( breakByMax))
);
};
console.log( tail( iterate( predMax, [ 10, 8, 6 ], 10 )));
// }
}());
//結果
[ [ 9, 8, 6 ],
[ 8, 8, 6 ],
[ 7, 8, 6 ],
[ 7, 7, 6 ],
[ 6, 7, 6 ],
[ 6, 6, 6 ],
[ 5, 6, 6 ],
[ 5, 5, 6 ],
[ 5, 5, 5 ],
[ 4, 5, 5 ] ]
なるだけHaskell風の関数にしてみました。
iterate()
もHaskell流に戻しました。
breakBy(x, ys)
はHaskellの break
にあたります。break (== x) ys
にあたります。
行は増えたけど、インデックス操作やslice()
で切り刻んでる感が隠れていい感じ。
と思ったのですが、何か問題があればコメントお願いします。
だれかこんなことやってる?とぐぐったらやっぱりいらっしゃいました。
JavaScript Haskell 化計画 息切れ版参考にさせていただきました。ありがとうございました。