Pythonで関数型プログラミングを体験しよう
皆さんは関数型言語をご存知でしょうか?
下記はプログラミング言語の系統図ですが、赤線で囲まれているのが関数型言語として分類されているプログラミング言語です。
下記にリンクを貼っておきます。
Pythonはオブジェクト指向言語ですが、関数型言語の影響も受けており、関数の組み合わせでコードを記述するプログラミング手法である関数型プログラミングを行うこともできます。
本記事では簡単なコードを使って関数型プログラミングについて紹介します。
用語の整理
関数型プログラミングでよく登場する用語としては次のようなものがあります。
第一級関数
無名関数(ラムダ式)
高階関数
第一級関数
プログラミング言語が第一級関数を持つと言われる場合、関数を他の関数への引数として渡したり、他の関数から返却したり、変数の値として代入したりすることができます。
MDNでの第一級関数の解説
下記にリンクを貼っておきます。
無名関数(ラムダ式)
プログラミング言語における無名関数とは、名前付けされずに定義された関数のことです。
無名関数を表現するための方法には様々なものがありますが、近年主流となているのはラムダ式による記法です。
ウィキペディアでの無名関数の解説
下記にリンクを貼っておきます。
高階関数
高階関数とは、第一級関数をサポートしているプログラミング言語において、関数を引数に取ったり関数を返したりする関数のことです。
ウィキペディアでの高階関数の解説
下記にリンクを貼っておきます。
とりあえず、次の3点を踏まえて本記事を読み進めてください。
1.Pythonは第一級関数をサポートしている
2.Pythonでは無名関数(ラムダ式)を定義できる
3.高階関数には「map」や「filter」などがある
関数型プログラミングのコード例
下記は2つの値の和と差を計算して返す簡単なコードですが、これを関数型プログラミングのコードに変えてみようと思います。
def add(num1, num2):
return num1 + num2
def sub(num1, num2):
return num1 - num2
print(add(10, 5))
print(sub(10, 5))
実行結果
15
5
次のようなcalcという高階関数を用意して、これを利用する形に上記のコードを変えてみます。(実行結果は同じですので省略します)
def calc(func, num1, num2):
return func(num1, num2)
関数型プログラミングのコード例1
add関数とsub関数の関数名をcalcに渡しています。
def add(num1, num2):
return num1 + num2
def sub(num1, num2):
return num1 - num2
def calc(func, num1, num2):
return func(num1, num2)
print(calc(add, 10, 5))
print(calc(sub, 10, 5))
関数型プログラミングのコード例2
add関数とsub関数を無名関数(ラムダ式)で定義して、それぞれをaddとsubという変数に代入して、その変数をcalcに渡しています。
add = lambda num1, num2: num1 + num2
sub = lambda num1, num2: num1 - num2
def calc(func, num1, num2):
return func(num1, num2)
print(calc(add, 10, 5))
print(calc(sub, 10, 5))
関数型プログラミングのコード例3
add関数とsub関数を無名関数(ラムダ式)で定義して、直接calcに渡しています。
def calc(func, num1, num2):
return func(num1, num2)
print(calc(lambda num1, num2: num1 + num2, 10, 5))
print(calc(lambda num1, num2: num1 - num2, 10, 5))
以上のように、いろいろな形でコードを書くことができます。
mapを使ってみよう
mapは高階関数の一つですが、mapを使うことでリストの各要素を変換することができます。どのような変換を行うかは渡される関数に依存します。
下記は[1, 2, 3, 4, 5, 6]というリストに対して、リストの各要素を2乗に変換した新しいリストを作成するコードです。
numbers = [1, 2, 3, 4, 5, 6]
new_numbers = []
for number in numbers:
new_numbers.append(number * number)
print(new_numbers)
実行結果
[1, 4, 9, 16, 25, 36]
上記のコードに対してmapを使用する形に変更したのが下記のコードです。
numbers = [1, 2, 3, 4, 5, 6]
new_numbers = list(map(lambda n: n * n, numbers))
print(new_numbers)
map関数にリストの要素を2乗に変換するラムダ式が渡されています。
filterを使ってみよう
filterも高階関数の一つですが、filterを使うことでリストの各要素に対してある条件に合致する要素を取り出すことができます。どのような条件かは渡される関数に依存します。
下記は[1, 2, 3, 4, 5, 6]というリストから3より大きい要素を取り出して新しいリストを作成するコードです。
numbers = [1, 2, 3, 4, 5, 6]
new_numbers = []
for number in numbers:
if (number > 3):
new_numbers.append(number)
print(new_numbers)
実行結果
[4, 5, 6]
上記のコードに対してfilterを使用する形に変更したのが下記のコードです。
numbers = [1, 2, 3, 4, 5, 6]
new_numbers = list(filter(lambda n: n > 3, numbers))
print(new_numbers)
filter関数に要素の値が3より大きいかを判定するラムダ式が渡されています。
リスト内包表記
リスト内包表記はリストを生成する簡潔な手段を提供します。
リスト内包表記を使用することで、リストのそれぞれの要素に対してある操作を行った結果を要素にしたリストの作成や、ある条件を満たす要素だけからなるリストの作成を簡潔な手段で実現することができます。
mapとリスト内包表記
下記のmapを使ったコードはリスト内包表記を使うことでより簡潔にコードを書くことができます。
numbers = [1, 2, 3, 4, 5, 6]
new_numbers = list(map(lambda n: n * n, numbers))
print(new_numbers)
リスト内包表記のコード
numbers = [1, 2, 3, 4, 5, 6]
new_numbers = [n*n for n in numbers]
print(new_numbers)
filterとリスト内包表記
下記のfilterを使ったコードはリスト内包表記を使うことでより簡潔にコードを書くことができます。
numbers = [1, 2, 3, 4, 5, 6]
new_numbers = list(filter(lambda n: n > 3, numbers))
print(new_numbers)
リスト内包表記のコード
numbers = [1, 2, 3, 4, 5, 6]
new_numbers = [n for n in numbers if n > 3]
print(new_numbers)
関数型プログラミングに興味を持たれた方へ
本記事では関数型プログラミングについてざっと紹介しましたが、「もっと関数型プログラミングについて知りたい」という方はPythonの公式ドキュメントの中に関数型プログラミングについて詳しく説明されている箇所がありますので、そちらをご確認いただくのが良いと思います。
下記にリンクを貼っておきます。