2013-05-21 7 views
15

異なる折り畳み関数を使用してタプルのリストを1つのタプルに折りたたみたいことがあります。たとえば、runStateの結果のリストを結合し、(ある意味で)結合状態と結合結果を得るためです。矢印を使ってタプルのリストを折り畳む

は、次の実装を検討してください。

wish :: (a -> a' -> a) -> (b -> b' -> b) -> (a,b) -> [(a', b')] -> (a,b) 
wish lfn rfn x xs = foldl (\(a,b) -> (lfn a) *** (rfn b)) x xs 

それは動作しますが、私はこのラムダについて不快に感じます。 lfn *** rfnそれ自体はタイプ(a,b) -> (a -> a', b -> b')ですが、これはパターンマッチングに頼らずにタプルに適切に適用する方法を見つけることができません。私が紛失している明確でエレガントな方法はありますか?それはタイプ(a,a') -> (a -> a, a' -> a') -> (a, a')のライブラリー関数か、まったく異なるアプローチかもしれません。

+2

BiApplicativeクラスのいくつかの並べ替えを行うだろう..おそらくどこかにハッキングのどこかにありますが、私は他の人に良いものと非難されないものをカバーするためにそれを残します。 – Carl

+0

http://squing.blogspot.com/2008/11/beautiful-folding.htmlとHackageのインスタンス化、http://hackage.haskell.org/package/ZipFold –

答えて

9

Control.Arrowは、より高い機能にはあまり注意を払っていません。あなたが本当に欲しいのは、機能foo :: (a -> a' -> a'') -> (b -> b' -> b'') -> (a,b) -> (a',b') -> (a'',b'')です。これは、アリティ2の機能のための(***)のアナログです。Data.Biapplicative(パッケージバイフォンターから)には、より一般的な署名biliftA2 :: Biapplicative w => (a -> b -> c) -> (d -> e -> f) -> w a d -> w b e -> w c fを持つそのような関数があります。 2要素タプルのためのBiapplicativeインスタンスがあるので、それだけで十分です。

私があなたのコードに対して見ることができる唯一の苦情は、ラムダのカリングが自明でないことです。私はより明示的な\(a,b) (a',b') -> (lfn a a', rfn b b')を好むかもしれません。

メモを編集する:必要な機能が存在しないと判断し、定義することを提案しました。 Carlのコメントに拍車をかけて、私はBiapplicativeのほうを見つけました(もっと一般的なタイプの署名は、Hoogleが私の提案した署名の下でそれを見つけるのを妨げていました)。

+0

'\(aを使って手動タプル分解を行う、b)(a '、b') - > ...ちょっとしたことは、すべての強力なライナーを書くためにいくつかの粋なコンセプトを使うという全目的に反するものです。 Biapplicativeを参照していただきありがとうございます、私はそれを調べます。 –

+0

Biapplicativeの '(<<**>>)に'(lfn *** rfn) 'を適用する必要がある型があるにもかかわらず、矢印の呼び出しが私にはあてはまりません。しかし、それは私の直感です。必ずしも明確ではないが、矢印ベースのアプローチは正しい。しかし私は明示的なラムダに ''(lfn \ 'biLiftA2 \' rfn) 'を優先します。 – isturdy

関連する問題