フロントエンドエンジニア芸人もりたけんじの関数型プログラミング勉強

【JavaScript/関数型プログラミング】抽象化

【JavaScript/関数型プログラミング】抽象化

p3
https://underscorejs.org/のコンソールで試す
※underscore.jsを使っています

[code language="javascript"]
function splat(fun){
return function(array){
return fun.apply(null, array);
}
}
var arrayelem = splat(function(x, y){ return x + y});
arrayelem([1, 2])
//3
[/code]

関数と配列を渡して呼ぶとその配列を関数の引数として実行することができる

[code language="javascript"]
function unsplat(fun){
return function(a, b){
return fun.call(null, _.toArray(arguments));
}
}
var fff = unsplat(function(array){return array.join(' ')});
fff(1,2);
"1 2"
fff('-', '$', '/', '!', ':');
"- $ / ! :"
[/code]

データと動作を隠蔽するということは関数を抽象の単位にする方法のひとつにすぎない
抽象とは個別の基本的な動作を保持し、あちこちで使い回すための簡単な方法を提供すること
[code language="javascript"]
var letter = ['a','b','c'];
letter[1];
//"b"
[/code]
配列のインデックス指定という基本動作を使い回すには
関数に閉じ込めておく以外に方法がない
[code language="javascript"]
function nth(a, index){
return a[index];
}
nth(letter, 1)
//"b"
[/code]
nth関数はインデックス指定可能なデータ型をもったデータから、有効なインデックスで指定される要素を返す

しかし予測しない動作をする
nth({}, 1)
undefined

与えられたものがインデックス指定可能なデータ型かどうか見分けるためにisIndexed関数を作る
抽象を提供する関数
[code language="javascript"]
function isIndexed(data){
return _.isArray(data) || _.isString(data);
}
[/code]

//抽象と別の抽象を組み合わせることでhthの完全な実装を行うことができる
[code language="javascript"]
function nth(a, index){
if(!_.isNumber(index)) console.log("indexは数値である必要があります");
if(!isIndexed(a)) console.log("インデックス指定可能でないデータ型です");
if((index < 0) || (index > a.length -1 )) console.log("指定されたインデックスは範囲外です");
return a[index];
}
nth({}, 1)
//インデックス指定可能でないデータ型です
nth(1, 1)
//インデックス指定可能でないデータ型です
nth([1,3],{})
//indexは数値である必要があります
nth('abc', 0)
//"a"
nth([2,4,5], 1)
//4
[/code]

isIndexed関数を使ってnthを抽象化したのと同様に2番目の要素を返す動作を抽象化したsecond関数を作ることができる

[code language="javascript"]
function second (a){
return nth(a, 1);
}
second(['a','b','c'])
//"b"
second("fogs");
//"o"
second({})
//インデックス指定可能でないデータ型です
[/code]
second関数を使ってnth関数の動作と異なる、しかし関連性のあるユースケースをあてがうことができる