This kind of problem reminds me the type inference made by SBCL.
Internally, SBCL transforms a type specifier (like
'array or
'string) into an object. The function that retrieves such object is
sb-kernel:specifier-type. The function that gives the specifier back is
sb-kernel:type-specifier. Types like
'(and string array) and
'(or integer character) are constructed using
sb-kernel:type-intersection and
sb-kernel:type-union.
I believe this is much similar to what you want to do, since SBCL can simplify some nested type unions / intersections similarly to the simplification of boolean expressions. You may refer to these functions (using M-. using Slime) and see if it helps.
- Code: Select all
cl-user> (sb-kernel:type-specifier
(sb-kernel:type-intersection (sb-kernel:type-union (sb-kernel:specifier-type 'array)
(sb-kernel:specifier-type 'fixnum))
(sb-kernel:type-union (sb-kernel:specifier-type 'array)
(sb-kernel:specifier-type 'integer))))
(or array fixnum)
cl-user> (sb-kernel:type-specifier
(sb-kernel:type-union (sb-kernel:type-intersection (sb-kernel:specifier-type '(integer -2 1))
(sb-kernel:specifier-type '(integer -1 2)))
(sb-kernel:type-intersection (sb-kernel:specifier-type '(integer -2 1))
(sb-kernel:specifier-type '(integer 0 3)))))
(integer -1 1)
cl-user> (sb-kernel:type-specifier
(sb-kernel:type-intersection (sb-kernel:type-union (sb-kernel:specifier-type 'character)
(sb-kernel:specifier-type 'fixnum))
(sb-kernel:type-union (sb-kernel:specifier-type 'character)
(sb-kernel:specifier-type 'array))))
character
cl-user> (sb-kernel:type-specifier
(sb-kernel:type-intersection (sb-kernel:type-union (sb-kernel:specifier-type 'character)
(sb-kernel:specifier-type '(satisfies foo)))
(sb-kernel:type-union (sb-kernel:specifier-type 'character)
(sb-kernel:specifier-type '(satisfies bar)))))
(or character (and (satisfies bar) (satisfies foo)))
Unfortunately, it seems not to be able to simplify the following expression, which is what you would want it to do:
- Code: Select all
cl-user> (sb-kernel:type-specifier
(sb-kernel:type-union (sb-kernel:type-intersection (sb-kernel:specifier-type 'fixnum)
(sb-kernel:specifier-type '(satisfies foo)))
(sb-kernel:type-intersection (sb-kernel:specifier-type 'fixnum)
(sb-kernel:specifier-type '(satisfies bar)))))
(or (and fixnum (satisfies foo)) (and fixnum (satisfies bar)))
;;; it would be better if it was (and fixnum (or (satisfies foo) (satisfies bar)))
;;; like in your example