Правила GraphEdit
GraphEdit
возвращает список, первым элементом которого является объект Graphics
, а остальными элементами являются правила, описывающие граф.Левая часть каждого правила - это строка, а не символ.Вы можете определить это, используя g // FullForm
.Чтобы извлечь правила графа, вы должны игнорировать первый элемент списка, например
"Graph" /. Drop[g, 1]
Имитация типов записей
Это разумный подход для реализации записикак типы данных, которые вы предлагаете:
graph={Verts->{1,2,3,4,5}, Edges->{1->2, 2->4, 4->4, 4->5}};
Это правда, что если бы Verts
и Edges
были назначены значения, то возникли бы "странные побочные эффекты".Однако есть несколько способов решить эту проблему.
Во-первых, в Mathematica чрезвычайно широко распространено соглашение о том, чтобы избегать присвоения значений (в частности, OwnValues
) символам с начальными буквами верхнего регистра.Вольфрам префикс всех переменных верхнего уровня с $
, например, $Context
.Если вы будете придерживаться этих соглашений, вы получите некоторую меру безопасности.
Во-вторых, есть положение для отдельных пространств имен, использующих Packages .В пределах определяемого вами пакета вы можете полностью контролировать привязки символов, которые вы используете в качестве имен полей.
В-третьих, вы можете использовать Защитить , чтобы имена полей не имелиприсвоенные им значения.
При реализации этих типов записей можно следовать идиоме LISP и определять функции конструктора и средства доступа.В примере с графиком эти функции могут выглядеть примерно так:
ClearAll[makeGraph, graphVertices, graphEdges]
makeGraph[vertices_, edges_] := {Verts -> vertices, Edges -> edges}
graphVertices[graph_] := Verts /. graph
graphEdges[graph_] := Edges /. graph
Эти функции будут использоваться следующим образом:
graph = makeGraph[{1,2,3,4,5}, {1->2,2->4,4->4,4->5}]
(* {Verts -> {1, 2, 3, 4, 5}, Edges -> {1 -> 2, 2 -> 4, 4 -> 4, 4 -> 5}} *)
graphVertices[graph]
(* {1, 2, 3, 4, 5} *)
graphEdges[graph]
(* {1 -> 2, 2 -> 4, 4 -> 4, 4 -> 5} *)
При использовании этой схемы ключи полей Verts
и Edges
может быть закрытым для пакета и защищенным, полностью исключая возможность случайного присвоения значения, разрушающего вещи.
В Mathematica очень часто используется выражение Head
для определения его типа.Мы можем соответствовать этому идиому и переопределить наши функции записи следующим образом:
ClearAll[makeGraph, graphVertices, graphEdges]
makeGraph[vertices_, edges_] := graphRecord[Verts -> vertices, Edges -> edges]
graphVertices[graphRecord[rules___]] := Verts /. {rules}
graphEdges[graphRecord[rules___]] := Edges /. {rules}
Единственное существенное различие между этими и предыдущими определениями состоит в том, что объект графа теперь представлен выражением формы graphRecord[...]
вместоиз {...}
:
graph = makeGraph[{1,2,3,4,5}, {1->2,2->4,4->4,4->5}]
(* graphRecord[Verts -> {1, 2, 3, 4, 5}, Edges -> {1->2, 2->4, 4->4, 4->5}] *)
graphVertices[graph]
(* {1, 2, 3, 4, 5} *)
graphEdges[graph]
(* {1 -> 2, 2 -> 4, 4 -> 4, 4 -> 5} *)
Почему изменения?Первая причина в том, что заголовок graphRecord
теперь точно определяет тип данных, тогда как раньше это был просто список.Во-вторых, мы можем определить дополнительные функции (квази-методы), которые будут действовать только на graphRecord
с и ничего больше.Например:
graphEdgeCount[r_graphRecord] := graphEdges[r] // Length
graphEdgeCount[x_] := (Message[graphEdgeCount::invArg, x]; Abort[])
graphEdgeCount::invArg = "Invalid argument to graphEdgeCount: ``";
Использование:
graphEdgeCount[graph]
(* 4 *)
graphEdgeCount["hi"]
Во время вычисления graphEdgeCount :: invArg: Неверный аргумент для graphEdgeCount: hi$ Aborted
В качестве окончательной проработки всего этого можно было бы определить макрофункцию, которая автоматически определяет все функции записи, учитывая тип и имена полей.Однако, поскольку этот ответ уже является TL; DR, его, вероятно, лучше всего оставить в качестве темы для другого вопроса.
Примечание. Если бы все эти функции были определены в контексте пакета, их имена будут использовать начальныестолицы (например, MakeGraph
вместо makeGraph
).Однако помните, что в Mathematica уже есть много встроенных символов, включающих слово Graph
.