Я хотел бы представить вики (набор документов, содержащих ориентированный граф) в Dhall. Эти документы будут отображаться в HTML, и я бы хотел, чтобы битые ссылки не создавались. На мой взгляд, это можно сделать либо сделав недопустимые графы (графы со ссылками на несуществующие узлы) через систему типов, либо написав функцию, возвращающую список ошибок в любом возможном графе (например, «В возможном графе»). X, узел A содержит ссылку на несуществующий узел B ").
Наивное представление списка смежности может выглядеть примерно так:
let Node : Type = {
id: Text,
neighbors: List Text
}
let Graph : Type = List Node
let example : Graph = [
{ id = "a", neighbors = ["b"] }
]
in example
Как видно из этого примера, этот тип допускает значения, которые не соответствуют действительным графам (нет узла с идентификатором «b», но узел с идентификатором «a» предусматривает соседа с идентификатором «b»). Более того, невозможно сгенерировать список этих проблем, сворачивая соседей каждого узла, потому что Dhall не поддерживает сравнение строк по конструкции.
Есть ли какое-либо представление, которое позволило бы либо вычислить список неработающих ссылок, либо исключить неработающие ссылки через систему типов?
ОБНОВЛЕНИЕ: Я только что обнаружил, что Naturals сопоставимы в Dhall. Поэтому я полагаю, что можно было бы написать функцию для идентификации любых недопустимых ребер («неработающие ссылки») и дублирования использования идентификатора, если идентификаторы были Naturals.
Оригинальный вопрос о том, можно ли определить тип графика, остается.
источник
Ответы:
Да, вы можете смоделировать безопасный по типу направленный, возможно, циклический граф в Dhall, например:
Это представление гарантирует отсутствие ломаных ребер.
Я также превратил этот ответ в пакет, который вы можете использовать:
Редактировать: Вот соответствующие ресурсы и дополнительные объяснения, которые могут помочь осветить то, что происходит:
Сначала начните со следующего типа Haskell для дерева :
Вы можете думать об этом типе как о ленивой и потенциально бесконечной структуре данных, представляющей то, что вы получили бы, если бы просто продолжали посещать соседей.
Теперь давайте представим , что выше
Tree
представление на самом деле является OURGraph
, просто переименовав тип данных дляGraph
:... но даже если бы мы хотели использовать этот тип, у нас нет способа напрямую моделировать этот тип в Dhall, потому что язык Dhall не обеспечивает встроенную поддержку рекурсивных структур данных. Так что же нам делать?
К счастью, на самом деле есть способ встроить рекурсивные структуры данных и рекурсивные функции в нерекурсивный язык, такой как Dhall. На самом деле есть два пути!
Первое, что я прочитал и познакомил меня с этим трюком, было следующее черновое сообщение Wadler:
... но я могу обобщить основную идею, используя следующие два типа Haskell:
... а также:
Способ
LFix
иGFix
работа заключается в том, что вы можете дать им «один слой» желаемого рекурсивного или «corecursive» типа (т.е.f
), и они затем дадут вам нечто настолько же мощное, что и желаемый тип, не требуя языковой поддержки для рекурсии или corecursion. ,Давайте использовать списки в качестве примера. Мы можем смоделировать «один слой» списка, используя следующий
ListF
тип:Сравните это определение с тем, как мы обычно определяем
OrdinaryList
использование обычного определения рекурсивного типа данных:Основное отличие состоит в том, что для этого
ListF
требуется один дополнительный параметр типа (next
), который мы используем в качестве заполнителя для всех рекурсивных / corecursive вхождений типа.Теперь, оснащенный
ListF
, мы можем определить рекурсивные и corecursive списки следующим образом:... где:
List
рекурсивный список, реализованный без языковой поддержки рекурсииCoList
это список corecursive, реализованный без поддержки языка для corecursionОба эти типа эквивалентны («изоморфны»)
[]
, что означает, что:List
и[]
CoList
и[]
Давайте докажем это, определив эти функции преобразования!
Итак, первым шагом в реализации типа Dhall было преобразование рекурсивного
Graph
типа:... к эквивалентному ко-рекурсивному представлению:
... хотя, чтобы немного упростить типы, я считаю, что легче специализироваться
GFix
на случаях, когдаf = GraphF
:У Haskell нет анонимных записей, таких как Dhall, но если бы они были, мы могли бы еще больше упростить тип, добавив определение
GraphF
:Теперь это начинает выглядеть как тип Dhall для a
Graph
, особенно если мы заменимx
наnode
:Тем не менее, есть еще одна сложная часть, которая заключается в том, как перевести
ExistentialQuantification
из Хаскелла в Далла. Оказывается, что вы всегда можете перевести экзистенциальную квантификацию в универсальную квантификацию (то естьforall
), используя следующую эквивалентность:Я считаю, что это называется "сколемизация"
Для более подробной информации смотрите:
... и этот последний трюк дает вам тип Dhall:
... где
forall (Graph : Type)
играет ту же роль, что иforall x
в предыдущей формуле, иforall (Node : Type)
играет ту же роль, что иforall y
в предыдущей формуле.источник