今年2018年最後は、関数型プログラミングについてのアウトプットです。拙いアウトプットですが、ご指摘等お待ちしております。
##関数型プログラミングとは
関数型プログラミングとは、解決しようとする問題をその問題に対して、その問題の性質を関数の組み合わせで記述するプログラミング手法。
これでは、全然自分は理解できなかったので、javascriptとScalaで実際に比べてみました。
ちなみに今回は、種別(category)と価格(price)のリストの合計金額を計算するプログラムを書きます。
##javascriptで関数型っぽく書かずにやってみると・・
function Menu(category,price){
this.category = category
this.price = price
};
var fish = new Menu("fish",200);
var pizza = new Menu("pizza",400);
var sushi = new Menu("sushi",100);
arr = [sushi,pizza,fish]
function totalFoodsPrice(arr){
totalPrice = 0;
for(var i = 0; i < arr.length; i++ ){
if(arr[i].category){
totalPrice += arr[i].price;
}
}
console.log(totalPrice);
}
totalFoodsPrice(arr)
上記のtotalFoodsPriceメソッドに注目してください。
このメソッドは、商品リストの受け取る事を仮定して、その商品の価格の合計を出力するメソッドです。
ここで関数型っぽい書き方ではない点挙げられるのは
・ 変数totalPriceという現在の価格を関数内で一旦「状態」を初期化して、その状態をfor文とif文を使い状態を変化させつつ、値を出力している点。
・変数iも、ループが行われるごとに、i++という命令文によって、変数iという「状態」を変化させながら、配列を繰り返し処理している点。
関数型では、問題を解決しようとする問題に対して変数や値、オブジェクト等を「状態」を変化させずに、関数の組み合わせのみで解決していきます。では、関数型プログラミングが推奨されているScalaではどうなるでしょうか
##Scalaで関数型プログラミング
case class Item(category: String, price: Int)
object myapp {
def totalFoodsPrice(itemList: List[Item]): Int = itemList match {
case Nil => 0
case Item(_ , price) :: otherItems => price + totalFoodsPrice(otherItems)
case _ :: otherItems => totalFoodsPrice(otherItems)
}
def main(arg: Array[String]) :Unit = {
val items = List[Item](
Item("fish",200),
Item("pizza",400),
Item("sushi",100)
)
println(totalFoodsPrice(items))
}
}
これも上記のtotalFoodsPriceメソッドに注目してください。
このメソッドは、商品リストを受け取り、その食品リストの合計を計算しています。
上記の処理と結果は変わりません。
また、「状態」main関数内で定義してはいますが、処理中に、一切その変数や値の「状態」を変化させていません。
この違いが命令型プログラミングと関数型プログラミングの違いのようです。
「状態」をプログラムの中で扱い、変化させていくことは、プログラムの動作をわかりづらくさせたり、テストやデバックを困難にする原因となります。(やたらと変数も多くなるイメージある・・)
これを避けて、プログラムの状態を変化させない関数を作成して、これを組み合わせて問題解決を行う手法が、関数型プログラミングのようです。
なお、関数型言語と呼ばれるものは、基本的に、関数型プログラミングが推奨されている言語の事で、関数型プログラミングがしやすいよう言語設計がされています。
しかし、関数型言語と呼ばれない言語でも、関数型っぽく書く事はできますので、認識の違いにご注意ください。
(自分もここで認識の違いがありました・・・)
他にも関数型プログラミング言語のメリットやデメリットはわかりやすく下記のリンクに記載されていますので、ご確認ください。
では、良いお年を・・