入力が無限に多くの値を取ることができる場合、リストを使用して非決定性をモデル化することは問題があります。例えば
pairs = [ (a,b) | a <- [0..], b <- [0..] ]
これは戻り[(0,1),(0,2),(0,3),...]
、最初の要素が ではないペアを表示することはありません0
。
Cantor ペアリング関数を使用して、リストのリストを 1 つのリストに折りたたむことで、この問題を回避できます。たとえば、バインドのような演算子を定義して、出力をよりインテリジェントに並べ替えることができます。
(>>>=) :: [a] -> (a -> [b]) -> [b]
as >>>= f = cantor (map f as)
cantor :: [[a]] -> [a]
cantor xs = go 1 xs
where
go _ [] = []
go n xs = hs ++ go (n+1) ts
where
ys = filter (not.null) xs
hs = take n $ map head ys
ts = mapN n tail ys
mapN :: Int -> (a -> a) -> [a] -> [a]
mapN _ _ [] = []
mapN n f xs@(h:t)
| n <= 0 = xs
| otherwise = f h : mapN (n-1) f t
これをモナドとしてまとめると、すべての可能なペアを列挙できます
newtype Select a = Select { runSelect :: [a] }
instance Monad Select where
return a = Select [a]
Select as >>= f = Select $ as >>>= (runSelect . f)
pairs = runSelect $ do
a <- Select [0..]
b <- Select [0..]
return (a,b)
これにより、
>> take 15 pairs
[(0,0),(0,1),(1,0),(0,2),(1,1),(2,0),(0,3),(1,2),(2,1),(3,0),(0,4),(1,3),(2,2),(3,1),(4,0)]
これははるかに望ましい結果です。ただし、代わりにトリプルを要求した場合、出力の順序は「適切」ではなく、最終的にすべての出力が含まれているかどうかさえわかりません-
>> take 15 triples
[(0,0,0),(0,0,1),(1,0,0),(0,1,0),(1,0,1),(2,0,0),(0,0,2),(1,1,0),(2,0,1),(3,0,0),(0,1,1),(1,0,2),(2,1,0),(3,0,1),(4,0,0)]
(2,0,1)
順序付けの前に表示されることに注意してください(0,1,1)
-私の直感では、この問題の適切な解決策は、アルゴリズムへの明示的な入力である可能性があるか、暗黙的に与えられる可能性がある「サイズ」の概念に従って出力を順序付けることです(この例では、入力の「サイズ」は入力リスト内の位置です)。入力を組み合わせる場合、組み合わせの「サイズ」は、入力のサイズの関数 (おそらく合計) にする必要があります。
私が見逃しているこの問題に対するエレガントな解決策はありますか?