Relational Specifications of Polymorphic Type Systems using Prolog
13th International Symposium on Functional and Logic Programming (FLOPS 2016), Kochi, Japan
2016-03-05 Friday (金) Session 4. Logic Programming for type systems
best viewed on Chrome, available online at https://slides.com/kyagrd/tiper-flops2016
Type
Inference
Prototyping
Engines from
Relational Specifications of
Type Systems
best viewed on Chrome, available online at https://slides.com/kyagrd/tiper-flops2016
Glories of Static Types in the Real World
Safety-Critical Software
e.g.,
- ISO 2662, Road Vehicles - Functional Safety
- ISO 2662-6: Table 1 (1c) Enforcement of strong typing
- EN 50128, Railway Industry Specific - Software safety review
- Table A.4 (8) - Strongly Typed Programming Language
9 Most In-Demand Prog. Lang. of 2016
Rank
|
Change | Language | Share | Trend |
---|---|---|---|---|
1 | Java | 24.2 % | +0.3 % | |
2 | ↑ | Python | 11.9 % | +1.2 % |
3 | ↓ | PHP | 10.7 % | -0.8 % |
4 | C# | 8.9 % | +0.1 % | |
5 | C++ | 7.6 % | -0.5 % | |
6 | C | 7.5 % | +0.1 % | |
7 | Javascript | 7.3 % | +0.3 % | |
8 | Objective-C | 5.0 % | -0.9 % | |
9 | ⇈ | Swift | 3.0 % | +0.4 % |
10 | R | 2.9 % | +0.3 % | |
11 | ⇊ | Matlab | 2.8 % | -0.3 % |
12 | Ruby | 2.3 % | -0.2 % | |
13 | Visual Basic | 1.8 % | -0.4 % | |
14 | VBA | 1.5 % | +0.1 % | |
15 | Perl | 1.1 % | -0.1 % | |
16 | Scala | 0.9 % | +0.2 % | |
17 | lua | 0.5 % | +0.0 % | |
© Pierre Carbonnelle, 2015 |
PYPL PopularitY of Prog. Lang. Index
Worldwide, Mar 2016 compared to a year ago:
Type Systems being re-invented
Lack of automated tools for building type systems
High development cost to adopt innovations from type theory & PL research
Inflexible and/or Verbose static type systems in mainstream langauges
Static Types
considered harmful, let's
use Dynamic Languages!
Oops, too painful to refactor/API-update
without static types
Okay, let's add static types
Flow type checker for JavaScript, TypeScript, mypy, Typed Clojure, Typed Lua, ... ..., and all those fancy projects on gradual typing
trending in the real world
Type Systems need to be
Flexible & Succinct
(highly Polymorphic)
Problem
(good Type Inference)
difficult to implement good type inference
for highly polymorphic type systems
Solution?
automatically generate implementations
from type system specifications
What is TIPER?
Lex/Yacc : Parsers
TIPER : Type Systems
the missing automation tool
in langauge frontend construction
Outline
-
Introduction
-
Relational Specifications
-
Logic Programming
-
Preliminary Results using Prolog
-
TIPER project - Progress & Plans
-
Related Work
Type System on paper
Type System implementation (algorithmic/functional description)
tyChk :: (Ctx, Exp, Type) -> Bool
tyChk(g, Var x, a) = (x,a) `elem` g
tyChk(g, Abs x e, Arr a b) = tyChk((x,a):g, e, b)
tyChk(g, App e1 e2, b) = case tyInf(g,e1) of { Arr a b -> tyChk(g,e2,a)
; _ -> False }
tyInf :: (Ctx, Exp) -> Maybe Type
tyInf(g, Var x) = lookup x gamma
tyInf(g, Abs x e) = ... -- actually need some more magic here
tyInf(g, App e1 e2) = case tyInf(gamma,e1) of { Arr a b
| tyChk(g,e2,a) -> Just b
; _ -> Nothing }
(Var)
(Abs)
(App)
Type System on paper
Problems with Algorithmic/Functional description
(Var)
(Abs)
(App)
- Gap from the original specification on paper
- Duplication inevitable (type check and type infer )
Type System on paper
Relational Specification
(Var)
(Abs)
(App)
- Reduces the gap from the description on paper
- Single Source of Truth (Don't Repeat Yourself )
Relational Spec. using Prolog
:- set_prolog_flag(occurs_check,true).
:- op(500,yfx,$).
type(C,var(X), T) :- first(X:T,C).
type(C,lam(X,E),A -> B) :- type([X:A|C], E, B).
type(C,E1 $ E2, B) :- type(C,E1,A->B),
type(C,E2,A).
first(K:V,[K1:V1|Xs]) :- K = K1, V = V1.
first(K:V,[K1:V1|Xs]) :- K\==K1, first(K:V, Xs).
Outline
-
Introduction
-
Relational Specification
-
Logic Programming
-
Preliminary Results using Prolog
-
TIPER project - Progress & Plans
-
Related Work
Logic Programming
-
Executable Relational Specification
-
Semantics exist for LP languages
-
incrementally builds up a substitution
-
can inspect intermediate results (not a black box)
-
-
Unification is a primitive operation in LP
-
basic building block for type inference algorithms
-
Why not something else?
-
Possible choices for Relational Spec.
-
Inductive Definitions in Interactive Theorem Provers
-
Logic Programming
-
Constraint Solvers / Automated Theorem Provers
-
-
Inductive Defs in ITPs are good for proofs
- Not usually best suited for execution
-
Solvers and ATPs are generally black box
-
No semantics, hard to inspect intermediate result
-
Solvers are usually difficult to extend
-
When to solve constraints to detect inconsistency is not always a trivial decision to make
-
Outline
-
Introduction
-
Relational Specification
-
Logic Programming
-
Preliminary Results using Prolog
-
TIPER project - Progress & Plans
-
Related Work
Simply-Typed Lambda Calculus
:- set_prolog_flag(occurs_check,true).
:- op(500,yfx,$).
type(C,var(X), T) :- first(X:T,C).
type(C,lam(X,E),A -> B) :- type([X:A|C], E, B).
type(C,E1 $ E2, B) :- type(C,E1,A->B),
type(C,E2,A).
first(K:V,[K1:V1|Xs]) :- K = K1, V = V1.
first(K:V,[K1:V1|Xs]) :- K\==K1, first(K:V, Xs).
Simply-Typed Lambda Calculus
:- set_prolog_flag(occurs_check,true).
:- op(500,yfx,$).
type(C,var(X), T) :- first(X:T,C).
type(C,lam(X,E),A -> B) :- type([X:A|C], E, B).
type(C,E1 $ E2, B) :- type(C,E1,A->B),
type(C,E2,A).
first(K:V,[K1:V1|Xs]) :- K = K1, V = V1.
first(K:V,[K1:V1|Xs]) :- K\==K1, first(K:V, Xs).
?- type([], lam(x,var(x)), A->A). % type checking true . ?- type([], lam(x,var(x)), T). % type inference T = (_G123->_G123) . ?- type([], E, A->A). % type inhabitation E = lam(_G234,var(_G234)) .
HM = STLC + Type Poly.
:- set_prolog_flag(occurs_check,true).
:- op(500,yfx,$).
type(C,var(X), T1) :- first(X:T,C), instantiate(T,T1).
type(C,lam(X,E), A -> B) :- type([X:mono(A)|C],E,B).
type(C,E1 $ E2, B ) :- type(C,E1,A -> B), type(C,E2,A).
type(C,let(X=E0,E1), T ) :- type(C,E0,A),
type([X:poly(C,A)|C],E1,T).
first(K:V,[K1:V1|Xs]) :- K = K1, V=V1.
first(K:V,[K1:V1|Xs]) :- K\==K1, first(K:V, Xs).
instantiate(mono(T),T).
instantiate(poly(C,T),T1) :- copy_term(t(C,T),t(C,T1)).
- Type binding X:A in STLC corresponds to X:mono(A) in HM
- poly(C,A) is a type scheme of A closed under the context C
- Instationation implemented by Prolog's built-in copy_term
HM = STLC + Type Poly.
:- set_prolog_flag(occurs_check,true).
:- op(500,yfx,$).
type(C,var(X), T1) :- first(X:T,C), instantiate(T,T1).
type(C,lam(X,E), A -> B) :- type([X:mono(A)|C],E,B).
type(C,E1 $ E2, B ) :- type(C,E1,A -> B), type(C,E2,A).
type(C,let(X=E0,E1), T ) :- type(C,E0,A), type([X:poly(C,A)|C],E1,T).
first(K:V,[K1:V1|Xs]) :- K = K1, V=V1.
first(K:V,[K1:V1|Xs]) :- K\==K1, first(K:V, Xs).
instantiate(mono(T),T).
instantiate(poly(C,T),T1) :- copy_term(t(C,T),t(C,T1)).
?- copy_term(t([],A->B), t([],T)). T = (_G993->_G994). % fresh vars: _G993, _G994 for A, B ?- copy_term(t([x:A],A->B), t([x:A],T)). T = (A->_G1024). % fresh vars: _G1024 for B only
Type Constructor Polymorphism
(a.k.a. higher-kinded polymorphism)
-- Tree :: (* -> *) -> * -> *
data Tree c a
= Leaf a -- Leaf :: Tree c a
| Node (c (Tree c a)) -- Node :: (c(Tree c a)) -> Tree c a
type BinTree a = Tree Pair a -- two children on each node
type Pair t = (t,t)
type RoseTree a = Tree List a -- varying number of children
type List a = [a]
HM only supports type polymorphism such as (1) but
not higher-kinded poly. such as (2) supported in Haskell
HM + TyCon Poly.
:- set_prolog_flag(occurs_check,true).
:- op(500,yfx,$).
kind(KC, var(X), K) :- first(X:T,KC).
kind(KC, F $ G, K2) :- kind(KC,F,K1->K2), kind(KC,G,K1).
kind(KC, A -> B, o) :- kind(KC,A,o), kind(KC,B,o).
type(KC,C,var(X), T1) :- first(X:T,C), instantiate(T,T1).
type(KC,C,lam(X,E), A -> B) :- type([X:mono(A)|C],E,B), kind(KC,A->B,o).
type(KC,C,E1 $ E2, B ) :- type(KC,C,E1,A -> B), type(KC,C,E2,A).
type(KC,C,let(X=E0,E1), T ) :- type(KC,C,E0,A),
type(KC,[X:poly(C,A)|C],E1,T).
first(K:V,[K1:V1|Xs]) :- K = K1, V=V1.
first(K:V,[K1:V1|Xs]) :- K\==K1, first(K:V, Xs).
instantiate(mono(T),T).
instantiate(poly(C,T),T1) :- copy_term(t(C,T),t(C,T1)).
(a specification which kind of works but not really ...)
Note. Not a correct spec. for TyCon Poly. but just for demo.
The "instantiate" predicate should be modified too.
HM + TyCon Poly.
(a specification which kind of works but not really ...)
?- type(KC, [], lam(x,var(x)), T).
KC = [_G1578:_G1581|_G1584],
T = (var(_G1578)->var(_G1578)) .
% OK, got the most general type at first :)
?- type(KC, [], lam(x,lam(y,var(x))), T).
KC = [_G1598:_G1601|_G1604],
T = (var(_G1598)->var(_G1598)->var(_G1598)) ;
KC = [_G1598:_G1601, _G1598:_G1612|_G1618],
T = (var(_G1598)->var(_G1598)->var(_G1598)) ;
KC = [_G1598:_G1601, _G1598:_G1612|_G1618],
T = (var(_G1598)->var(_G1598)->var(_G1598)) ;
KC = [_G1598:_G1601, _G1609:_G1612|_G1618],
T = (var(_G1609)->var(_G1598)->var(_G1609))
% Well, the most general type in 4th solution :(
gets even more unpleasant for HM + TyCon Poly + Kind Poly + ...
Workaround for extensions of HM
- The Problem happens because we have
two different expectations for Type Variables- in type: unifiable logic variables
- in kind: atomic variables
- A Workaround
-
Delay kind goals until type goals are resolved
- used DCG to delay kind goals during type infer and call them later after some preprocessing - For further details see our paper
- Prolog Specs available online at TIPER homepage
-
Delay kind goals until type goals are resolved
- Prolog has features to exploit for workarounds but it is not ideal as a specification language for type systems
Lessons from our work
-
Logic Programming can be effective for
Executable Relational Specifications of type systems
- Prolog is not a perfect tool for this purpose. It lacks
- search strategy suitable for type inference problems
- resolving goals at conceptually different levels with possibly different set of unification variables
- order irrelevant unification to properly support specifications for extensible records with Row Poly.
- may be neat to have lazy coinductive resolution
Outline
-
Introduction
-
Relational Specification
-
Logic Programming
-
Preliminary Results using Prolog
-
TIPER project - Progress & Plans
-
Related Work
(a) Experiment / Research
- Develop type system specs
using off-the-shelf LP tools - Identify limitations of existing LP tools for type system spec.
- Investigate theories to help overcome those limitations
(b) Tool Design & Impl.
- Parser integration
- Error handling
- Frontend: surface lang. with Prolog-like syntax
- Backend: portable LP eDSL or kernel (e.g. μKanren) to target possibly multiple language environments
Activities of the TIPER Project
continuous integration by multiple iterations of (a) and (b)
Progress / Ongoing Work
- Polymorphic Type System Specifications using Prolog
- HM + Type Constructor Poly. + Kind Poly. + etc.
- HM + TyCon Poly. + Kind Poly. + Row Poly
- type inference with extensible records
- inference only, not supporting type annotation
- Exploring microKanren
- STLC, HM, HM+TC Poly, HM+TC Poly+Kind Poly are ported into an Haskell impl. of microKanren
- see https://github.com/kyagrd/ukanren for details
- Investigating ingredients for Extensible Records
- (open-ended) set unification and map unification
- see my gh-repo ExtensibleRecordsWithSetMembLP
Plans for TIPER
- Features to support
- Polymorphisms over Type / Type Constructor / Kind
- Extensible Records with Row Polymorphism
- First-Class Polymorphism and Modules
- Some FL features such as Type Classes and GADTs
- Some OOPL features such as subtyping
- SW Architecture
- Prolog-like syntax frontend (or something better?)
- parser integration & error handling
- portable backend (LP kernel implemented as eDSL)
- Theories to investigate
- alternative resolution semantics (e.g., coinductive)
- better/flexible search strategies
- handling extra-logical features (e.g., fresh var. gen.)
Outline
-
Introduction
-
Relational Specification
-
Logic Programming
-
Preliminary Results using Prolog
-
TIPER project - Progress & Plans
-
Related Work
Related Work
-
Embedded DSL for LP
-
miniKanren and microKanren ( http://miniKanren.org ) ported to more than a dozen of programming languages
-
-
Coinductive flavors of LP
-
Type Inference by Coinductive Logic Programming
(Ancona, Lagorio, Zucca 2009) in post TYPES 2008 -
Proof Relevant Corecursive Resolution in FLOPS 2016
(Fu, Komendantskaya, Schrijvers, Pond 2016)
-
-
Delimited Continuations for Prolog in ICLP 2013
(Schrijvers, Demoen, Desouter, Wielemaker 2013) -
Membership-Constraints and Complexity in Logic Programming with Sets (Stolzenburg 1996) in FroCoS 1996
Prior attempts in similar spirit
-
Executable Specification of Static Semantics note: Typol
(Despeyroux. 1984) in Semantics of Data Types 1984 -
Extraction of Strong Typing Laws from Action Semantics Definitions (Doh, Schmidt. 1992) in ESOP 1992
-
Type Inference with Constrained Types note: HM(X)
(Odersky, Sulzmann, Wehr. 1999) TAPOS, 5(1):33-55 -
Type System for the Massses in Onward 2015
(Grewe, Erdweg, Wittmann, Mezini 2015) -
And there are more frameworks for type checker development
-
TyS: a framework to facilitate the dev. of OO type checkers
-
Typical: Taking the Tedium Out of Typing
-
Conclusion
- There have been
- practical work on automated dev. of type checkers
- mostly for lang. with no parametric polymorphism
- sometimes demo HM example for inference showcase
- automating "HM + constraints" at a pedagogical level but not including more adv. features (TyCon poly, Row poly.)
- practical work on automated dev. of type checkers
- What we want is
- to build a practical framework
- automate development of type checking & inference
- support advanced polymorphic features
Executable Relational Specifications of Polymorphic Type Systems using Prolog
By 안기영 (Ahn, Ki Yung)
Executable Relational Specifications of Polymorphic Type Systems using Prolog
Talk slides for FLOPS 2016
- 2,501