Декартовой продукт Haskell из бесконечных списков
Я хочу создать векторное пространство из пары оснований, которая выглядит примерно так:
genFromPair (e1, e2) = [x*e1 + y*e2 | x <- [0..], y <- [0..]]
Когда я проверяю вывод, хотя он sems, как будто я получаю [0, e2, 2*e2,...]
(т.е. x
никогда не становится выше 0). Какой смысл имеет смысл, когда я думаю о том, как написать код, чтобы сделать это понимание списка.
Я написал некоторый код, чтобы взять расширяющиеся "оболочки" из начала координат (сначала интегралы с нормой 0, затем с нормой 1, затем норма 2...), но это своего рода раздражающее и специфическое для Z ^ 2 - я 'd придется переписать его для Z ^ 3 или Z [i] и т.д. Есть ли более чистый способ сделать это?
Ответы
Ответ 1
Пакет data-ordlist имеет некоторые функции, которые чрезвычайно полезны для работы с отсортированными бесконечными литами. Один из них mergeAllBy
, который объединяет бесконечный список бесконечных списков с использованием некоторой функции сравнения.
Идея состоит в том, чтобы построить бесконечный список списков, чтобы y
фиксировался в каждом списке, а x
- растет. Пока мы можем гарантировать сортировку каждого списка и сортировку глав списков в соответствии с нашим заказом, мы получим объединенный отсортированный список.
Вот пример:
import Data.List.Ordered
import Data.Ord
genFromPair (e1, e2) = mergeAllBy (comparing norm) [[x.*e1 + y.*e2 | x <- [0..]] | y <- [0..]]
-- The rest just defines a simple vector type so we have something to play with
data Vec a = Vec a a
deriving (Eq, Show)
instance Num a => Num (Vec a) where
(Vec x1 y1) + (Vec x2 y2) = Vec (x1+x2) (y1+y2)
-- ...
s .* (Vec x y) = Vec (s*x) (s*y)
norm (Vec x y) = sqrt (x^2 + y^2)
Попытка этого в GHCi получить ожидаемый результат:
*Main> take 5 $ genFromPair (Vec 0 1, Vec 1 0)
[Vec 0.0 0.0,Vec 0.0 1.0,Vec 1.0 0.0,Vec 1.0 1.0,Vec 0.0 2.0]
Ответ 2
Вы можете посмотреть на свое пространство как на дерево. В корне дерева выбирается первый элемент, а в его дочернем элементе вы выбираете второй элемент.
Здесь ваше дерево определено с помощью пакета ListTree:
import Control.Monad.ListT
import Data.List.Class
import Data.List.Tree
import Prelude hiding (scanl)
infiniteTree :: ListT [] Integer
infiniteTree = repeatM [0..]
spacesTree :: ListT [] [Integer]
spacesTree = scanl (\xs x -> xs ++ [x]) [] infiniteTree
twoDimSpaceTree = genericTake 3 spacesTree
Это бесконечное дерево, но мы можем перечислить его, например, в порядке DFS:
ghci> take 10 (dfs twoDimSpaceTree)
[[],[0],[0,0],[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7]]
Порядок, который вы хотите, в дереве-речи, является вариантом поиска наилучшего поиска для бесконечных деревьев, где предполагается, что дети узлов дерева отсортированы (вы не можете сравнить все дети node как в обычном поиске наилучшего поиска, потому что их бесконечно много). К счастью, этот вариант уже реализован:
ghci> take 10 $ bestFirstSearchSortedChildrenOn sum $ genericTake 3 $ spacesTree
[[],[0],[0,0],[0,1],[1],[1,0],[1,1],[0,2],[2],[2,0]]
Вы можете использовать любую норму, которая вам нравится для ваших расширяющихся оболочек, вместо sum
выше.
Ответ 3
Использование фрагмента diagonal
из CodeCatalog:
genFromPair (e1, e2) = diagonal [[x*e1 + y*e2 | x <- [0..]] | y <- [0..]]
diagonal :: [[a]] -> [a]
diagonal = concat . stripe
where
stripe [] = []
stripe ([]:xss) = stripe xss
stripe ((x:xs):xss) = [x] : zipCons xs (stripe xss)
zipCons [] ys = ys
zipCons xs [] = map (:[]) xs
zipCons (x:xs) (y:ys) = (x:y) : zipCons xs ys
Ответ 4
Piggybacking on hammar reply: Его подход выглядит довольно легко распространяться на более высокие размеры:
Prelude> import Data.List.Ordered
Prelude Data.List.Ordered> import Data.Ord
Prelude Data.List.Ordered Data.Ord> let norm (x,y,z) = sqrt (fromIntegral x^2+fromIntegral y^2+fromIntegral z^2)
Prelude Data.List.Ordered Data.Ord> let mergeByNorm = mergeAllBy (comparing norm)
Prelude Data.List.Ordered Data.Ord> let sorted = mergeByNorm (map mergeByNorm [[[(x,y,z)| x <- [0..]] | y <- [0..]] | z <- [0..]])
Prelude Data.List.Ordered Data.Ord> take 20 sorted
[(0,0,0),(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(1,1,1),(2,0,0),(0,2,0),(0,0,2),(2,1,0),(1,2,0),(2,0,1),(0,2,1),(1,0,2),(0,1,2),(2,1,1),(1,2,1),(1,1,2)]