Functional Python Programming という本を読んでいたら、 Wrap-Unwrap Pattern というものを知ったので、ちょっとメモ.

https://www.amazon.com/Functional-Python-Programming-Expressive-Implementations-ebook/dp/B00T96XC0Q

公式

unwrap(process(wrap(iterable)))
  • wrap() ラッパー
  • unwrap() アンラッパー ラッパーで処理したものをもとに戻す.
  • process() 処理したい手続き
  • iterable 処理したいデータ

ラッパーは、iterable なデータをタプルに加工する. タプルを利用するのは、タプルが immutable なデータ構造だから.

例: 最大値を求める

以下、python による例です.

以下のデータ構造で身長が最大の人を調べる.

  • 太郎: 170
  • 次郎: 160
  • 三郎: 180
students = [("Taro", 170), ("Jiro", 160), ("Saburo", 180)]

max 関数は、そのままでは利用できない.

>>> max(students)
('Taro', 170)

ラッパーでタプルを作成する. wrap 関数は、generator expression ともいう.

def wrap(students):
    return ((student[1], student) for student in students)

def unwrap(data):
    length, student = data
    return student

パターンを適用.

unwrap(max(wrap(students)))

>>> unwrap(max(wrap(students)))
('Saburo', 180)

その他

wrap 関数をいちいち定義するのは面倒なので、lambda が利用される.

>>> max(map(lambda s: (s[1], s), students))[1]
('Saburo', 180)

map を利用する場合の方が、generator expression よりも、高速らしい.

unwrap の操作でタプルの一番目、二番目を取り出すのは常套手段. なので、Haskell には、fst,snd という関数が用意されている.

  • fst: タプルの 1 番目の要素を取り出し
  • snd: タプルの 2 番目の要素を取り出し