Я искал что-то похожее: способ дешево и легко ориентироваться (который включает в себя переход «назад») вдвойне бесконечный список списков.Вот мой взгляд на это.
Если я внимательно прочитаю ответы других, то, что я здесь представляю, это не действительно молния: пока навигация амортизируется O (1), памятьиспользуется zipper структура сеть никогда не освобождается.С другой стороны, он должен быть достаточно узким для того, чтобы «ячейки» могли быть общими, независимо от того, какой путь мы выберем, - это такая топология, которую мы хотели бы видеть в двумерном списке списков.
Чтобы компенсировать это, список списков, использованных для его генерации, в конечном итоге должен остаться без ссылок и для сбора мусора.
data FakeZip2D a = Z2 { z2Val :: a
, goUp :: !( Maybe (FakeZip2D a) )
, goDown :: Maybe (FakeZip2D a)
, goLeft :: !( Maybe (FakeZip2D a) )
, goRight :: Maybe (FakeZip2D a)
}
fromList2 :: [[a]] -> Maybe (FakeZip2D a)
fromList2 xss = head (head zss) where
extended = [ repeat Nothing ] ++
map (\z -> [Nothing] ++ z ++ repeat Nothing) zss ++
[ repeat Nothing ]
zss = zipWith4' row xss extended (drop 1 extended) (drop 2 extended)
row xs prev cur next = Just <$> zipWith5' Z2 xs (tail prev) (tail next)
cur (drop 2 cur)
-- totally inspired by https://stackoverflow.com/a/54096748/12274
zipWith4' f (a:as) (b:bs) ~(c:cs) ~(d:ds) =
f a b c d : zipWith4' f as bs cs ds
zipWith5' f (a:as) (b:bs) ~(c:cs) (d:ds) ~(e:es) =
f a b c d e : zipWith5' f as bs cs ds es
Структура данных должна быть самоочевидной.Вверх и влево можно позволить себе быть строгим, потому что мы строим из односвязных списков.AFAIK, нет смысла делать их ленивыми в Haskell, так как они все равно не позволят чему-либо выйти за рамки.
Решетка построена рекурсивно, расширяя границы предоставленного ввода с помощью Nothing
.Достаточно ленивые варианты zipWith
, в которых я нуждался, вдохновлены ответами на другую серию моих вопросов по теме.
Вот он в действии:
demo :: IO ()
demo = do
let multList2 = [[ i*j | j <- [0..] ] | i <- [0..] ]
multZ2 = fromList2 multList2
let rows = iterate (>>= goDown) multZ2
cols = map (iterate (>>= goRight)) rows
putStrLn "Multiplication table"
mapM_ (print . map z2Val) $ take 5 $ map (catMaybes . take 5) cols
putStrLn "List of squares"
let goDiag = goRight >=> goDown
print $ map z2Val $ take 25 $ catMaybes $ iterate (>>= goDiag) multZ2
putStrLn "Convoluted list of squares"
let goDiag' = goDown >=> goRight >=> goUp >=> goLeft >=> goDiag
print $ map z2Val $ take 25 $ catMaybes $ iterate (>>= goDiag') multZ2
Интерфейс, вероятно, можно сделать еще проще в использовании, опустив Maybe
s.Естественно, на свой страх и риск.
Это может быть немного не по теме, так как это не настоящая молния, но это решило мою проблему;и поскольку этот вопрос возник, когда я впервые искал решение, я публикую его здесь с намерением помочь кому-то другому.