Typechecker Plugin Constraint Solving

Good day, I am currently developing a typechecker plugin for GHC for realizing an idea regarding types based on regular expressions to describe the contents of a string. This is done using type-level literals to denote a particular regex. Additionally there are additional constraints for working with such types. One of those constraints is called Intersectable and denotes whether an intersection between two regexes would be possible in the sense that there is some common alphabet between them. Furthermore there is a type-level function that calculates the actual intersection between two regex types and returns the resulting regex type: type family Intersectable (a :: Symbol) (b :: Symbol) :: Constraint type family Intersection (a :: Symbol) (b :: Symbol) :: Symbol Now i've created a typechecker plugin that resolves such constraints by using a finite-automata representation of the regexes to do the actual work. While my plugin is already able to proof progams where regexes are fully applied, i.e. they can reduce terms to a single regex and then verify the constraints accordingly or reject them, it fails to type "intermediate" functions. As a small example assume the following program: checkFour :: Intersectable a "[0-4]" => RgxString a -> RgxString (Intersection a "[0-4]") checkFour a = undefined checkEight :: Intersectable a "[0-8]" => RgxString a -> RgxString (Intersection a "[0-8]") checkEight a = undefined test = checkFour . checkEight -- this fails to type correctly test2 = checkFour $ checkEight $ (RgxString :: RegexString ".*") -- this works fine The constraint solver wants me to proof the following constraints for test: tcPluginSolve given = [] derived = [] wanted = [ [WD] irred_a2GV {0}:: Intersectable (Intersection a0 "[0-8]") "[0-4]" (CNonCanonical), [WD] irred_a2GY {0}:: Intersectable a0 "[0-8]" (CNonCanonical)] My plugin reduces the first constraint to Intersectable a0 [0-4] as regex intersection is commutative so i can intersect [0-8] with [0-4] first. But i haven't found out yet how i would tell the compiler to put this reduced constraint to the type signature instead of the current one where the constraint got dropped at all instead of at least remain unnormalized, and the return type remains unnormalized as well: RgxString a -> RgxString (Intersection (Intersection a "[0-8]") "[0-4]") I'd need to tell the typechecker somehow that (Intersection (Intersection a "[0-8]") "[0-4]") is equal to Intersection a "[0-4]" so it substitutes it accordingly. My idea is that i have to generate given type and function equality constraints during the typechecking telling it that those representations are equal, but i am really not sure what kind of constraints i need. CTyEqCan for instance seems to require a TyVar on one side while i though i could generate something like Intersection (Intersection a "[0-8]") "[0-4]" ~ Intersection a "[0-4]" I have already tried a lot but there is little documentation on the whole constraint solving process and i am slowly getting stuck. Thanks for helping!
participants (1)
-
Armin Wurzinger