Можно ли обнаружить совместное использование в Haskell?

В схеме примитив eq? проверяет, являются ли его аргументы одним и тем же объектом. Например, в следующем списке

(define lst
  (let (x (list 'a 'b))
    (cons x x)))

Результат

(eq? (car x) (cdr x))

истинно, и, кроме того, оно верно, не заходя в (car x) и (cdr x). Это позволяет вам писать эффективные тесты равенства для структур данных, которые имеют большой доступ.

В Хаскелле все еще возможно? Например, рассмотрим следующую реализацию двоичного дерева

data Tree a = Tip | Bin a (Tree a) (Tree a)

left  (Bin _ l _) = l
right (Bin _ _ r) = r

mkTree n :: Int -> Tree Int
mkTree 0 = Tip
mkTree n = let t = mkTree (n-1) in Bin n t t

который имеет доступ на каждом уровне. Если я создам дерево с let tree = mkTree 30, и я хочу посмотреть, равны ли left tree и right tree, наивно мне приходится пересекать более миллиарда узлов, чтобы обнаружить, что они являются одним и тем же деревом, что должно быть очевидно из-за данных совместное использование.

Я не ожидаю, что есть простой способ обнаружить совместное использование данных в Haskell, но я задавался вопросом, что типичные подходы к решению таких проблем, когда было бы хорошо обнаружить совместное использование для целей эффективности (или, например, для обнаружение циклических структур данных).

Есть ли unsafe примитивы, которые могут обнаружить совместное использование? Есть ли известный способ построения структур данных с явными указателями, чтобы вы могли сравнить равенство указателя?

Ответ 1

Там много подходов.

  • Создайте уникальные идентификаторы и поместите все на конечной карте (например, IntMap).
  • Уточненная версия последнего выбора - сделать явный график, например. используя fgl.
  • Используйте стабильные имена.
  • Используйте IORef s (см. также), которые имеют как Eq и Ord, вне зависимости от типа содержимого.
  • Существуют библиотеки для наблюдаемого обмена.
  • Как упоминалось выше, существует reallyUnsafePtrEquality#, но вы должны понимать, что на самом деле небезопасно, прежде чем использовать его.

См. также этот ответ об избежании вообще проверок равенства.

Ответ 2

В Haskell, чистом языке, это невозможно.

Но в его реализации в GHC есть лазейки, такие как

В любом случае использование этого в обычном коде было бы очень унииоматичным; я мог представить себе, что создание высокоспециализированной библиотеки для чего-то (memoizatoin, хеш-таблицы, что угодно), который затем обеспечивает разумный чистый API, может быть приемлемым.