Я полагаю, что вы можете использовать эту библиотеку, но вам придется внести незначительные изменения в вашу структуру данных.В частности, вам придется переписать его как функтор подписи вместо рекурсивного типа данных.
Вот что это значит: ваш тип CType
является рекурсивным, поскольку содержит другие экземпляры CType
в одном изего конструкторы (CArr
).Переписать рекурсивный тип данных в качестве сигнатуры означает создание типа данных, который принимает параметр типа, и использовать этот параметр типа везде, где вместо этого вы будете использовать рекурсию.Например:
data CTypeF a
= CVar Int
| CArr a a
| CInt
| CBool
deriving (Eq, Data)
Теперь в вашей программе, где вы ранее проходили около CType
с, вам нужно будет работать с чем-то более сложным, чем просто CTypeF
.Ваш новый CType
-эквивалент должен применить CTypeF
по кругу к себе.К счастью, Term
сделает это за вас, поэтому импортируйте Data.Comp.Term
и замените все ваши CType
с Term CTypeF
с.(Конечно, вы всегда можете использовать псевдоним type CType = Term CTypeF
, чтобы сохранить некоторую типизацию; просто учтите, что Term CTypeF
буквально не совпадает с вашим исходным CType
; вам нужно добавить несколько конструкторов Term
в места, которыепроизводить и потреблять CType
с.)
Наконец, чтобы использовать механизм объединения в compdata
, вам понадобится экземпляр HasVars
для CTypeF
, которыйидентифицирует ваш CVar
конструктор как переменную.Вам также нужно будет сделать CTypeF
и Functor
и Foldable
, но если вы включите языковые функции DeriveFunctor
и DeriveFoldable
, GHC может сделатьэто для вас - это чисто механический процесс.
Когда вы запускаете unify
, вам нужно убедиться, что вы делаете это в контексте, где ошибка монады m
и тип переменной v
однозначно.Есть много способов сделать это, но для примера, скажем, что мы используем простейшую монаду ошибок Either e
в качестве m
, и, конечно, вы захотите, чтобы v
было Int
,Так что вы можете написать:
f = Term (CVar 2)
g = Term CInt
-- By matching against Left and Right, we're letting GHC know that unify
-- should return an Either; this disambiguates `m`
main = case unify [(f, g)] of
Left _ -> print "did not unify"
Right subst -> doMoreWork subst
-- The Int here disambiguates `v`
doMoreWork :: Subst CTypeF Int -> IO ()
doMoreWork subst = undefined -- fill in the blank!