web-dev-qa-db-ja.com

関数型プログラミングにおけるバナナの分割と融合とは何ですか?

これらの用語は私の大学のコースで言及されました。すばやくグーグルすると大学の論文がいくつか表示されましたが、簡単な説明を探しています。

22
Gaurav Abbi

すでに2つの回答が提供されていますが、ここでは「バナナ分割」についてはまだ説明していません。

「バナナ、レンズ、封筒、有刺鉄線による機能的プログラミング、エリック・マイヤー・マーテン・フォッキンガ、ロス・パターソン、1991」で実際に定義されています。その記事は、Squiggolを多用しているため(私にとって)読みにくいものです。ただし、「フォールドの普遍性と表現力に関するチュートリアル、Graham Hutton、1999年」には、解析しやすい定義が含まれています。

foldを使用してタプルを生成する簡単な最初の例として、数値のリストのsumおよびlengthを計算する関数sumlengthを考えます。

sumlength :: [Int] → (Int,Int)
sumlength xs = (sum xs, length xs)

foldを使用して関数sumおよびlengthの定義を簡単に組み合わせると、関数sumlengthfoldの単一のアプリケーションとして再定義できます。数のリストから数のペアを生成します:

sumlength = fold (λn (x, y) → (n + x, 1 + y)) (0, 0)

この定義は、2つの別々の走査ではなく、引数リストを1回走査するだけなので、元の定義よりも効率的です。この例から一般化すると、同じリストへのfoldのアプリケーションのペアは常に組み合わせることができ、いわゆる「バナナスプリット」にアピールすることで、ペアを生成するfoldの単一のアプリケーションを提供できます。 foldのプロパティ(Meijer、1992)。このプロパティの奇妙な名前は、fold演算子がバナナに似た角かっこ(| |)を使用して記述されることがあり、ペアリング演算子が分割と呼ばれることがあるという事実に由来しています。したがって、それらの組み合わせはバナナスプリットと呼ぶことができます。

4

つまり、これは実際にはMeijerと " Functional Programming with Bananas、Lenses、Envelopes and Barbed Wire "と呼ばれるいくつかの論文を参照しています。基本的な考え方は、再帰的なデータ型をとることができるということです。言うように

 data List = Cons Int List | Nil

型変数に再帰を因数分解できます

 data ListF a = Cons Int a | Nil

Fを追加した理由は、これが今ではファンクタだからです。リストを模倣することもできますが、ひねりを加えています。リストを作成するには、リストタイプをネストする必要があります

type ThreeList = ListF (ListF (ListF Void)))

元のリストを復元するには、これを無限にネストし続ける必要があります。これにより、タイプListFFが得られます。

  ListF ListFF == ListFF

これを行うには、「固定小数点タイプ」を定義します

  data Fix f = Fix {unfix :: f (Fix f)}
  type ListFF = Fix ListF

演習として、これが上記の方程式を満たしていることを確認する必要があります。これで、最終的にバナナ(カタモフィズム)を定義できます!

  type ListAlg a = ListF a -> a

ListAlgsは「リスト代数」のタイプであり、特定の関数を定義できます

  cata :: ListAlg a -> ListFF -> a
  cata f = f . fmap (cata f) . unfix

さらに

  cata :: ListAlg a -> ListFF -> a
  cata :: (Either () (Int, a) -> a) -> ListFF -> a
  cata :: (() -> a) -> ((Int, a) -> a) -> ListFF -> a
  cata :: a -> (Int -> a -> a) -> ListFF -> a
  cata :: (Int -> a -> a) -> a -> [Int] -> a

見覚えがあります? cataは、右折とまったく同じです。

本当に興味深いのは、リストだけではなく、これを実行できることです。この「ファンクターの固定小数点」で定義された型にはcataがあり、それらすべてに対応するには、型シグネチャを緩和するだけです。

  cata :: (f a -> a) -> Fix f -> a

これは実際には 私が書いた というカテゴリー理論の一部からインスピレーションを得ていますが、これはHaskell側の要です。

20
Daniel Gratzer

Jozefgが回答を提供しましたが、質問に回答したかどうかはわかりません。 「融合法則」は次の論文で説明されています。

フォールドの普遍性と表現力に関するチュートリアル、GRAHAM HUTTON、1999

基本的には、いくつかの条件下では、関数の構成を組み合わせ(「融合」)、単一の折りたたみに折りたたむことができるので、基本的に

h・フォールドg w =フォールドf v

この平等の条件は

h w = v
h(g x y)= f x(h y)

「バナナ分割」または「バナナ分割法」は記事から

バナナ、レンズ、封筒、有刺鉄線を使った関数型プログラミング、エリックマイヤーマールテンフォッキンガ、ロスパターソン、1991

残念ながら、この記事はBird-Meertens形式を使用しているため、解読するのが非常に難しく、頭と尾を作成できませんでした。私が「バナナ分割法」を理解している限り、同じ議論で2つのフォールドを操作している場合、それらを1つのフォールドにマージできると述べています。

7
Jackie