Я хочу написать rename
функцию для замены String
имен (которые представляют иерархические идентификаторы) в моих AST
именами GUID
(целыми числами) из таблицы символов, переносимой как скрытое состояние в Renamer
монада.
У меня есть тип AST a
, который параметризован по типу имени. Имена в листах АСТ имеют тип Name a
:
data Name a = Name a
Что облегчает нацеливание на них с помощью трансформатора SYB.
Парсер набирается (игнорируя возможность ошибки для краткости):
parse :: String -> AST String
и я хочу, чтобы набиралась функция rename
:
rename :: AST String -> Renamer (AST GUID)
Можно ли использовать SYB для преобразования всех Name String
в Name GUID
с помощью преобразователя:
resolveName :: Name String -> Renamer (Name GUID)
и все другие значения от c String
до c GUID
путем преобразования их потомков и вставки их обратно вместе с тем же конструктором, хотя и с другим параметром типа?
Функция everywhereM
близка к тому, что я хочу, но она может преобразовывать только c a -> m (c a)
, а не c a -> m (c b)
.
Мое альтернативное решение (кроме написания вручную) - удалить параметр типа из AST
и определить Name
следующим образом:
data Name = StrName String
| GuidName GUID
, чтобы переименование было набрано:
rename :: AST -> Renamer AST
заставить его работать с everywhereM
. Тем не менее, это оставляет возможность того, что AST
может все еще содержать StrName
после переименования. Я хотел использовать систему типов, чтобы формально зафиксировать тот факт, что переименованный AST
может содержать только GUID
имен.