Slide 1

Slide 1 text

AN OVERVIEW OF THE TYPE SYSTEM

Slide 2

Slide 2 text

Intro “PureScript is a small strongly-typed programming language that compiles to JavaScript” ● Learn more at purescript.org or on #purescript ● Goals: ○ Build the language I want to use every day ○ Explore how types can improve web programming ○ Try out some new type system ideas ○ Provide a fun project for Haskell OSS newcomers

Slide 3

Slide 3 text

Agenda ● Recap some Haskell extensions ● Talk about the implementation ● Demo some novel features ● Future work

Slide 4

Slide 4 text

Some Haskell Extensions

Slide 5

Slide 5 text

Type Classes class Eq a where eq :: a -> a -> Boolean instance eqBoolean :: Eq Boolean where eq True True = True eq False False = True eq _ _ = False instance eqList :: Eq a => Eq (List a) where ...

Slide 6

Slide 6 text

Higher-kinded types data Free f a = Pure a | Impure (f (Free f a)) class Functor f where map :: (a -> b) -> f a -> f b

Slide 7

Slide 7 text

Functional Dependencies class MonadState s m | m -> s where state :: (s -> Tuple s a) -> m a data Z data S n -- Peano naturals class Add n m r | n m -> r instance addZ :: Add Z n n instance addS :: Add n m r => Add (S n) m (S r)

Slide 8

Slide 8 text

Functional Dependencies Functional dependencies give us “type-level Prolog” Examples: ● purescript-generics-rep ● purescript-type-map by @LiamGoodacre ● purescript-type-lang by @LiamGoodacre

Slide 9

Slide 9 text

Higher-rank polymorphism runST :: forall a. (forall h. ST h a) -> a hiding :: forall result . (forall impl. Interface impl => Proxy impl -> result) -> result

Slide 10

Slide 10 text

Implementation Notes

Slide 11

Slide 11 text

Phases of the type checker 1. Check/infer types and gather constraints 2. Solve constraints 3. goto 2 until no more constraints can be solved 4. Final cleanup pass and generalization

Slide 12

Slide 12 text

Unification Types can be partially solved during type checking Unification happens when we learn that two (partially known) types must be equal (Example)

Slide 13

Slide 13 text

Bidirectional type checking Separate the type checker into two modes: inference and checking In practice, there are several judgments: ● Inference ● Checking ● Function application ● Subsumption

Slide 14

Slide 14 text

Skolemization When checking something has a polymorphic type, we need to generate a fresh type variable which does not unify with other types. These are called skolem constants. At the end of type checking, we need to check that no skolem constants escaped their scope. (Example)

Slide 15

Slide 15 text

Type Classes When we apply a function which has type class constraints, we insert a placeholder for a dictionary into the expression. This is called elaboration or dictionary-passing. These placeholders will get replaced during the solving phase. (Example)

Slide 16

Slide 16 text

Functional Dependencies Functional dependencies can cause new unifications to happen during solving. These unifications can cause more instances to become applicable, solving new constraints. So the solver loops until no new type information can be learned. (Example)

Slide 17

Slide 17 text

Cleanup ● Check no skolems escaped ● Generalize any unsolved type variables ● Generalize over any unsolved constraints

Slide 18

Slide 18 text

Novel Features

Slide 19

Slide 19 text

Row Polymorphism: Extensible Records getter :: forall a r . { foo :: a | r } -> a getter rec = rec.foo setter :: forall a r . a -> { foo :: a | r } -> { foo :: a | r } setter a rec = rec { foo = a }

Slide 20

Slide 20 text

Row Polymorphism: Extensible Effects getFromNetwork :: forall eff . Eff (network :: NETWORK | eff) X main :: Eff (console :: CONSOLE, network :: NETWORK) Unit main = do x <- getNetworkResource logShow x

Slide 21

Slide 21 text

Row Polymorphism: Implementation ● Rows are maps from labels to types (actually, association lists) ● Rows can have duplicate labels ● Unification of rows must ignore order of different labels but preserve order of duplicates ● “row of k”, spelled # k is a new kind for each kind k (Example)

Slide 22

Slide 22 text

-- a magic type class class Union r1 r2 r3 | r1 r2 -> r3, r1 r3 -> r2 merge :: forall r1 r2 r3. . Union r1 r2 r3 => Record r1 -> Record r2 -> Record r3 See purescript-records by @doolse, also Ermine Row Constraints: Unions

Slide 23

Slide 23 text

Polymorphic Labels -- another magic type class class RowCons l a r1 r2 | l a r1 -> r2, l r1 r2 -> a prop :: forall l a r1 r2. . RowCons l a r1 r2 => SProxy l -> Lens’ (Record r2) a See purescript-profunctor-lenses

Slide 24

Slide 24 text

Polymorphic Labels: Variants ctor :: forall l a r1 r2. . RowCons l a r1 r2 => SProxy l -> Prism’ (Variant r2) a See purescript-variants by @natefaubion

Slide 25

Slide 25 text

Type-Directed Search flatten :: List (Maybe Int) -> Maybe (List Int) flatten = ?IForgot Hole 'IForgot' has the inferred type List (Maybe Int) -> Maybe (List Int) You could substitute the hole with one of these values: Data.Monoid.mempty :: forall m. Monoid m => m Data.Traversable.sequence :: forall a m t. Traversable t => Applicative m => t (m a) -> m (t a)

Slide 26

Slide 26 text

Type-Directed Search: Implementation ● Brute-force search through the context ● Uses subsumption to test for compatibility See @kritzcreek’s thesis :)

Slide 27

Slide 27 text

Future Work

Slide 28

Slide 28 text

Instance Chains class TypeEq a b r | a b -> r instance typeEq :: TypeEq a a True instance typeNotEq :: TypeEq a b False -- ← overlapping! instances instance typeEq :: TypeEq a a True instance typeNotEq :: TypeEq a b False

Slide 29

Slide 29 text

Constraint Kinds class MapRow (c :: Symbol -> Type -> Type -> Constraint) (r1 :: # Type) (r2 :: # Type) -- auto-generated instances instance mapEmpty :: MapRow c () () instance mapNonEmpty :: (c l a b, MapRow xs ys) => MapRow (l :: a | xs) (l :: a | ys)

Slide 30

Slide 30 text

References

Slide 31

Slide 31 text

Haskell 98 ● Typing Haskell in Haskell Mark P. Jones

Slide 32

Slide 32 text

Higher-rank Polymorphism ● Complete and Easy Bidirectional Typechecking for Higher-Rank Polymorphism Joshua Dunfield and Neelakantan R. Krishnaswami ● HMF: Simple Type Inference for First-Class Polymorphism Daan Leijen

Slide 33

Slide 33 text

Type Classes and Functional Dependencies ● How to make ad-hoc polymorphism less ad hoc Philip Wadler ● Type Classes with Functional Dependencies Mark P. Jones ● Instance Chains: Type Class Programming Without Overlapping Instances J. Garrett Morris and Mark P. Jones

Slide 34

Slide 34 text

Extensible Records ● Row Polymorphism Isn’t Subtyping Brian McKenna ● Extensible records with scoped labels Daan Leijen ● First-class labels for extensible rows Daan Leijen ● Koka: Programming with Row Polymorphic Effect Types Daan Leijen ● Ermine compiler

Slide 35

Slide 35 text

Questions?