Редактирование / обновление графиков в Haskell
Я использую данные.График график для моделирования моделирования в Haskell. Моделирование ограничено 2D-сеткой, которую моделирует мой график. Узел в каждой точке сетки ниже будет содержать, возможно, тип молекулы, так что может быть молекула присутствует или просто ничего.
1 - 2 - 3
| | |
4 - 5 - 6
| | |
7 - 8 - 9
Я настроил это представление, но когда дело доходит до обновления положения молекулы, я чувствую, что иду по длинному пути вокруг проблемы. То, что я сделал до сих пор, разделило все узлы на список узлы. Я написал функцию для замены двух элементов в этом списке узлов. Но теперь, когда я прихожу к zip все вместе, я прихожу в проблемы, потому что для генерации нового графа мне нужен список вершин, которые я легко получаю из функции графа вершин. Но мне также нужно застегнуть это со списком вершин, к которым прикасается ребро. К Сожалению Данные.Функция Graph's Edge Graph возвращает список кортежей типа Edge, который, насколько я вижу, не сразу полезен для создания графика, хотя я мог бы написать функцию для получения вершин списка, которые имеют ребра к вершине. Кажется, что для меня достаточно работы, чтобы задаться вопросом, не хватает ли мне точки, есть ли функция Graph, которая просто берет график и возвращает график с обновленным узлом?
2 ответов
FGL имеет этот отличный механизм "контекста", который позволяет вам сопоставлять шаблон в запросе графика. Вы можете представить это как подтягивание выбранной вершины, чтобы она сидела сбоку от остальной части графика. Это позволяет посмотреть, как эта вершина связана с остальной частью графика.
{-# LANGUAGE TupleSections #-}
import Control.Applicative
import Control.Arrow
import Data.Graph.Inductive
-- Example graph from SO question.
graph :: Gr (Maybe Int) ()
graph = mkGraph (map (id&&&Just) [1,2,3,4,5,6,7,8,9])
(map (\(x,y) -> (x,y,())) $
concatMap gridNeighbors [1..9])
where gridNeighbors n = map (n,)
. filter ((&&) <$> valid <*> not . boundary n)
$ [n-3,n-1,n+1,n+3]
valid x = x > 0 && x < 10
boundary n x = case n `rem` 3 of
0 -> x == n + 1
1 -> x == n - 1
_ -> False
-- Swap the labels of nodes 4 and 7
swapTest g = case match 4 g of
(Just c4, g') -> case match 7 g' of
(Just c7, g'') -> setLabel c4 (lab' c7) &
(setLabel c7 (lab' c4) &
g'')
_ -> error "No node 7!"
_ -> error "No node 4!"
where setLabel :: Context a b -> a -> Context a b
setLabel (inEdges, n, _, outEdges) l = (inEdges, n, l, outEdges)
вы можете попробовать запустить swapTest graph
чтобы увидеть, что метки для узлов 4 и 7 в схеме меняются местами.
есть ли особая причина, по которой вы используете графики здесь? Мне кажется, что набор ребер в значительной степени фиксирован и что ваши сетки меняются только в положениях молекул.
почему бы вам просто не использовать массивы или другую структуру данных, которая позволяет сосредоточиться на молекулах и их положениях? Например:
import Data.Array
data Molecule = H2O | CO2 | NH3
type Grid = Array (Int, Int) (Maybe Molecule)
-- creates an empty grid
grid :: Int -> Int -> Grid
grid m n = array ((0, 0), (m - 1, n - 1)) assocs
where
assocs = [((i, j), Nothing) | i <- [0 .. m - 1], j <- [0 .. n - 1]]
-- swap the molecules at the specified indices
swap :: (Int, Int) -> (Int, Int) -> Grid -> Grid
swap (i, j) (u, v) grid =
grid // [((i, j), grid ! (u, v)), ((u, v), grid ! (i, j))]
-- etc.
(Если у вас есть веские причины использовать графики, я, конечно, полностью вне линии здесь, и в этом случае я извиняюсь...)