Подтвердить что ты не робот

Функции возможных циклических структур данных

Если у меня есть рекурсивный ADT

data MyType = A | B | C MyType | D MyType MyType

Я мог бы написать функцию, чтобы определить, содержит ли экземпляр MyType a A так:

hasA :: MyType -> Bool
hasA A = True
hasA B = False
hasA (C x) = hasA x
hasA (D x y) = (hasA x) || (hasA y)

Это будет работать для ациклических экземпляров, но оно не останавливается для циклических структур, например.

let x = C x in hasA x

Вместо этого в этом примере он должен вернуться False. В других случаях (используя D) он ошибочно не останавливается, а не возвращает True.

Итак, вопрос в том, как наиболее легко писать такие функции, как hasA, которые работают над циклическими структурами? Racket имеет особенно приятную функцию для этого в виде define/fix, что позволяет вам выполнять функцию типа hasA, как и предполагалось, и возвращать False для структуры в примере выше, с едва ли дополнительным кодом. Есть ли способ сделать что-то подобное в Haskell? Есть ли расширение для него?

Изменить: теперь я обнаружил, что define/fix на самом деле макрос, созданный Matt Might, который использует возможности метапрограммирования Racket, в особенности, но это не делает его менее важной особенностью Racket. Может быть, этот макрос можно воспроизвести в Haskell?

4b9b3361

Ответ 1

Ключевыми словами для поиска в Hackage являются наблюдаемый обмен. Пакет data-reify в этих результатах выглядит особенно актуальным:

data-reify предоставил [sic] возможность превратить рекурсивные структуры в явные графики. Многим (неявным или явным) рекурсивным структурам данных может быть предоставлена ​​эта способность через экземпляр типа. Это дает альтернативу использованию Ref для наблюдаемого обмена.