効率性について何を言うべきかわかりませんが、何が起こっているのかを分析して、少なくともいくつかの異なる機能を得ることができます。特定の機能は最適化できる可能性がありますが、必要なものを正確に明確にすることが重要です。
質問を言い換えてみましょう:ある集合 X、ある二項関係 R、およびある二項演算 + について、集合 Q = {x+y | } を生成します。x in X、y in X、xRy}。したがって、あなたの例では、 X はリストのセットであり、 R は「 x と y の両方に少なくとも1つの要素がある場合に限り xRy 」であり、 + は++
.
単純な実装では、set-builder 表記自体をコピーするだけかもしれません
shareElement :: Eq a => [a] -> [a] -> Bool
shareElement xs ys = or [x == y | x <- xs, y <- ys]
v1 :: (a -> a -> Bool) -> (a -> a -> b) -> [a] -> [b]
v1 (?) (<>) xs = [x <> y | x <- xs, y <- xs, x ? y]
その後p = v1 shareElement (++) :: Eq a => [[a]] -> [[a]]
、あなたが望むものを達成するかもしれません。おそらくそうではないことを除いて。
Prelude> p [[1], [1]]
[[1,1],[1,1],[1,1],[1,1]]
最も明白な問題は、4 つのコピーを取得することです。2 つはリストをそれ自体とマージすることで、2 つはリストを相互に「両方向で」マージすることで作成されます。問題が発生するのList
は、 が と同じではないため、一意のSet
ものを削除できないためです。もちろん、それは簡単な修正です。Set
どこでも使用します
import Data.Set as Set
v2 :: (a -> a -> Bool) -> (a -> a -> b) -> Set.Set a -> Set.Set b
v2 (?) (<>) = Set.fromList . v1 (?) (<>) . Set.toList
もう一度試すことができp = v2 (shareElement
ますSet.toList) Set.union
Prelude Set> p $ Set.fromList $ map Set.fromList [[1,2], [2,1]]
fromList [fromList [1,2]]
これはうまくいくようです。のインスタンスにすることはできないList
ため、またはその制約のために、「通過」する必要があることに注意してください。Set
Monad
Applicative
Ord
には多くの失われた動作があることにも注意してくださいSet
。たとえば、リスト内の注文情報を破棄するか、両方を処理する必要がx <> y
ありy <> x
、関係が対称である場合に戦います。
いくつかのより便利なバージョンは次のように書くことができます
v3 :: Monoid a => (a -> a -> Bool) -> [a] -> [a]
v3 r = v2 r mappend
そして、関係がたとえば等式関係であると仮定すると、より効率的なものを構築できます。それ以来、O(n^2)
操作を行う代わりに、関係の分割 (剰余類) の数でそれを行うことO(nd)
ができます。d
一般的に、これは非常に興味深い問題です。