Treatment of Types in an Implementation of λProlog Organized
around Higher-Order Pattern Unification
Xiaochu QiDepartment of Computer Science and
Engineering University of Minnesota
Types in Logic Programming Languages
descriptive notion: typed Prolog
parametric polymorphism
type nil (list A).
type :: A -> (list A) -> (list A).
type append (list A) -> (list A) -> (list A) -> o.
Types in Logic Programming Languages
prescriptive notion: λProlog mixed usage of parametric and ad hoc polymorphism
type print_int int -> o.
type print_str string -> o.
type print A -> o.
print X :- print_int X.
print X :- print_str X.
print X.
The Nature of Polymorphism in λProlog a polymorphic version of the simply typed λ-
calculus
atomic types: including type variables
the intuitive meaning of a term t :σ{t :σ’ |σ’ is a closed instance of σ }
The Roles of Types in λProlog a strongly typed language
type declarations for constants inferring types for all subterms
prevent run-time failures well-typedness: compile time type-checking
participate in unification
∀:: ∀nil ∀append F ∀c
A Prefix of Mixed Quantifiers
?- (F)(append (c::nil) nil (F c)).
universal variable
existential variable
constant
?- (F)∀c(append (c::nil) nil (F c)).
∀c ∀:: ∀nil ∀append F
Types of Constants and Variables
The occurrences of a constant can have different types.
The occurrences of a universal or existential variable must always have identical types.
type nil (list A).type :: A -> (list A) -> (list A).
(1 :: nil)
(“a” :: nil)(1:int :::int->(list int)->(list int) nil:(list int))
(“a”:string :::string->(list string)->(list string) nil:(list string))
Higher-Order Unification
determine the identity of constants
decide the structures of unifiers
Types are associated with every variable and constant.
Higher-Order Pattern Unification
determine the identity of constants
a universal or existential variable: always has identical types in different occurrences
can have a polymorphic type, which could be specialized during unification
Typed Higher-Order Pattern Unification
processing terms in a top-down manner iterative usage of:
term simplification phase: simply non-existential variable head applications
binding phase decide the structure of bindings for existential variables
invariant: Terms to be unified always have identical types.
Typed Higher-Order Pattern Unification
term simplification phase: constant heads: examine (specialize) the types of
these constants others: already have identical types
binding phase: identical types of the entire terms identical types of relevant variables no comparison on constants No need for type examination
∀g F ∀c X ∀a
type g A -> B.τ(c)= A->B τ(a)= Cτ(X)= C->A τ(F)= (A->B)->int
<(g (c (X a))) , (g (F c))>
<(g:B->D (c:A->B (X:C->A a:C)), (g:int->D (F:(A->B)->int c:A->B))>
(r-r): {<B, int>} <c:A->int (X:C->A a:C), F:(A->int)->int c:A->int>
(r-f): {<F, λc(c (H c))>} ∀g H F ∀c X ∀a <X:C->A a:C, H:(A->int)->A c:A->int>
(f-f): {<X, λc(H’ a)>, <F, λc(c (H’ c))>}
∀1 ∀”a” ∀f X Y ∀c
type f A -> B -> C.τ(c)= A->B τ(X)= A τ(Y)= B
<(f X “a” (c X)) , (f 1 Y (c Y))>
<f:A->string->B->C X:A “a”:string (c:A->B X:A), f:int->A->B->C 1:int Y:A (c:A->B Y:A)>
Maintain Types with Constants
only associating types with constants
Exp1: ∀g F ∀c X ∀a <(g:B->D (c:A->B (X:C->A a:C)), (g:int->D (F:(A->B)->int c:A->B))>
<(g:B->D (c (X a)), (g:int->D (F c))>
Exp2: ∀1 ∀”a” ∀f X Y <f:A->string->B->C X:A “a”:string (c:A->B X:A), f:int->A->B->C 1:int Y:A (c:A->B Y:A)>
<f:A->string->B->C X “a” (c X), f:int->A->B->C 1 Y (c Y)>
Maintain instances of type variables
well-typedness with respect to type declarations compile time type-checking
instances of type variables run time type-checking
(:::[list A] (:::[A] X nil:[A]) nil:[list A])
Exp1: <(g:B->D (c (X a)), (g:int->D (F c))> <(g:[B,D] (c (X a)), (g:[int,D] (F c))> (:: (:: X nil) nil)
(:::(list A)->(list (list A))->(list (list A)) (:::A->(list A)->(list A) X nil:(list A)) nil:(list (list A)))
Type Preservation
Type variables occurring in target types have been checked at a upper level.
Constant function symbols: type variables not occurring in target types
Non-function constants: no need to maintain types
type :: A -> (list A) -> (list A).type nil (list A).
(:::[list A] (:::[A] X nil:[A]) nil:[list A])
(:: (:: X nil) nil)
type g (A -> B) -> A.type a int -> B.
(:::[int] (g:[int,B] a:[int,B]) nil:[int])
(:: (g [B] a) nil)
Teyjus: id A (:: A X L) (:: A X K) :- id A L K.
Type Processing Effort in Compiled Unification
type id (list A) -> (list A) -> o.
id nil nil.
id (X::L) (X::K) :- id L K.
?- id (1::nil) T.
Our scheme: id A (:: X L) (:: X K) :- id A L K.
Teyjus: ?- id int (:: int 1 nil) T.Our scheme: ?- id int (:: 1 nil) T.
bind (T, (:: A S2 K));
bind (A, int); bind (S2, X);
<(:: A X K), T>(write mode)
<(:: A X L), (:: int 1 nil)>(read mode)
bind (T, (:: S2 K)); <(:: X K), T>
<(:: X L), (:: 1 nil)>
Type Processing in Compiled Unification over<id (X::L) (X::K), id (1::nil) T>
bind (A, int); <A, int>
bind (X, 1);bind (L, nil);
Type generality
Typed Prolog : type p σ1 -> … -> σn -> o.
p t1 … tn :- b1, …, bm. τ(t1)= σ1, …, τ(tn)= σn
Every sub-term of ti is type preserving. Only type general and preserving programs are well-
typed.
λProlog : mixed usage of parametric and ad hoc polymorphism
Type generality in λProlog
type print A -> o.
type print_int int -> o.
type print_str string -> o.
print X :- print_int X.
print X :- print_string X.
print X.
type generality and preservation property should hold on every clause head defining a predicate.
Type generality in λProlog
type foo A -> o.
foo X :- print X.
type variables of the clause head should not be used in body goals.
Conclusion
Type examination is necessary in higher-order pattern unification.
Reduce type association and run-time type examination
constant function symbols separate static and dynamic information take advantage of the type preservation property
Top Related