280 likes | 476 Views
Cayenne: A language with dependent types. Lennart Augustsson Presenter: Umut Acar. Cayenne (Hot Stuff!). Haskell-like language with dependent types Haskell is non-strict (lazy), declarative Types are first class Records can have types as their components Dependent types:
E N D
Cayenne: A language with dependent types Lennart Augustsson Presenter: Umut Acar
Cayenne (Hot Stuff!) • Haskell-like language with dependent types • Haskell is non-strict (lazy), declarative • Types are first class • Records can have types as their components • Dependent types: • The type of a function can depend on the argument value, • \x -> if (x>2) then 1 else true • A record component can depend on some other component • Records can be used as signatures and structures • Big win over Haskell---Haskell support for modules is no good • Big win over SML---no need for a module language Type Refinements for Programming Languages
The downside • Type checking of Cayenne is undecidable! Type Refinements for Programming Languages
Writing printf in Cayenne • Type of printf depends on its first parameter, format string • printf (“Hello world\n”) • printf :: String -> Int • printf (“Number = %d\n”, n) • printf: String * Int -> Int • How can we even write the type for printf? Type Refinements for Programming Languages
Can Compute type of printf • printf::(fmt::string) ->(PrintfType fmt) • printf (“%s = %d”, “five”,5) :: string -> string -> int -> int • We can “construct” types: types are expressions! PrintfType :: String ! # PrintfType (Nil) = String PrintfType ('%':'d':cs) = Int -> PrintfType cs PrintfType ('%':'s':cs) = String -> PrintfType cs ... PrintfType ('%':_:cs) = PrintfType cs PrintfType (_:cs) = PrintfType cs Type Refinements for Programming Languages
The Code for printf • printf calls pr which returns the appropriate function depending on the format string printf::(fmt::String) -> PrintfType fmt printf fmt = pr fmt “” where pr “” res = res pr (‘%’:’d’: cs) res = \i -> pr cs (show (i) ++ res) .... Type Refinements for Programming Languages
Records • Record types start with the keyword sig • Record values start with the keywors struct • Example: type person = sig age::int salary::int address::string poorJoe::person = struct age = 25 salary = 20000 address = “254 Joesplace Street” Type Refinements for Programming Languages
Modules with records, signatures • Record types correspond to signatures of SML • Example: An integer set type IntSet = sig type T empty :: T singleton :: Int -> T union :: T -> T -> T member :: Int -> T -> Bool Type Refinements for Programming Languages
Modules with records, structures • Use records for structures of ML • Example: An integer set listSet::IntSet listSet = struct type t = Int List empty = [] singleton i = [i] union a b = a @ b member i a = foldr (\x -> x=i) a False unionFindSet::IntSet unionFindSet = struct .... Type Refinements for Programming Languages
Modules are first class values • Can pick an implementation for IntSet at run time intset = if (input size > 30) then listSet else unionFindSet ... s1 = intset.singleton 1 s2 = intset.singleton 2 s12 = intset.union s1 s2 Type Refinements for Programming Languages
The Core Cayenne Language expr :: = (varid :: type) -> expr -- fun type \(varid :: type) -> expr -- lambda expr expr -- application data {conid { type } | } -- sum type conid@type -- constructor case varid of { arm } :: type -- case analysis sig { sign } -- signatures struct {defn} -- structures expr . lblid -- record selection varid -- variable #_1; #_2,... -- type of types arm ::= (condid {varid}) -> expr; varid -> expr sign ::= lblid :: type; lblid :: type = expr defn ::= vis lblid :: type = expr; vis ::= private | public abs abs ::= abstract |concrete types ::= expr Type Refinements for Programming Languages
The Core Language • Core Cayenne language has three type forming constructs • Dependent functions • Data types (sums) • Dependent records (products) • No syntactic distinction between expression and types • type ::= expr Type Refinements for Programming Languages
The Core Language: dependent functions • Functions and application are defined as • Note the occurrence of a variable in a function type • printf :: (fmt::string) -> PrintfType fmt expr ::= (varid :: type) -> expr -- fun type \(varid :: type) -> expr -- lambda expr expr -- application Type Refinements for Programming Languages
The Core Language: sum types • Sum types are mostly standard except • Constructor names need not be unique accross different types • Therefore we need a type signature for constructors, i.e., @ expr ::= data {conid { type } | } -- sum type conid@type -- constructor case varid of { arm } :: type -- case analysis arm ::= (condid {varid}) -> expr varid -> expr Type Refinements for Programming Languages
Example: Sum Types • The type for case expression must be specified • In general, it is not possible to find the type of a case Bool = data False | True -- define booleans case l of (Nil) -> True (Cons h t) -> False :: Bool case l of (Nil) -> 1 (Cons h t) -> “Hello” :: (case l of True -> Int False -> String) Type Refinements for Programming Languages
The Core Language: records • Records are enriched to support modules • Record types are signatures, values are structures • Signatures can contain translucent sums • Structures have private or public abstract/concrete members expr :: = sig { sign } -- signatures struct {defn} -- structures expr . lblid -- record selection sign ::= lblid :: type lblid :: type = expr -- translucent sums defn ::= vis lblid :: type = expr vis ::= private | public abs abs ::= abstract |concrete Type Refinements for Programming Languages
A simple record example • The visibility keywords determine the signature of a structure struct private x :: Int = 1 public abstract y :: Int = x+1 public concrete z :: Int = x+2 :: sig y :: Int z :: Int = 3 --translucent sums Type Refinements for Programming Languages
Modules with records • Modules are units of compilation • They are records with syntactic sugar • Module names reside in the global name space • Module names are distinguished by a $ in their name Type Refinements for Programming Languages
Example: A tree module module $tree = struct concrete data Tree a = Leaf | Node (Tree a) a (Tree a) abstract depth :: (a :: #) |-> Tree -> Int depth (Leaf) = 0 depth (Node l _ r)= 1 + depth l ‘max’ depth r Type Refinements for Programming Languages
The signature for the tree module • Exposes the types and values of all concrete constructors sig -- Tree is a type constructor Tree :: # -> # = data Leaf | Node (Tree a) a (Tree a) Leaf :: (a ::#) |-> Tree a = \a::#) |-> Leaf@(Tree a) Node :: (a::#) |-> Tree a -> a -> Tree a -> Tree a = \(a ::#) |-> \(l::Tree a) -> \(x::a) -> \(r:: Tree a) -> Node@(Tree a) l x y depth :: (a :: #) |-> Tree a -> Int Type Refinements for Programming Languages
Typing Rules: Dependent Function Types Type Refinements for Programming Languages
Typing Rules: Lambda and Application Type Refinements for Programming Languages
Typing Rules: Sum Types Type Refinements for Programming Languages
Typing Rules: Product Types, signatures Type Refinements for Programming Languages
Typing Rules: Products, structures Type Refinements for Programming Languages
Erasing Types • No run-time decision can be made based on the value of a (type) expression • No such (casetype e of Int -> ....) • Types can be erased • the author argues that no type information need to be maintained at run time • Cardelli conjectures that, with dependent types, types will be needed at run time[Cardelli, Phase Distinction] Type Refinements for Programming Languages
The state of Cayenne • Has a prototype implementation and has been tested on a few thousands of lines of code • Test programs included Haskell programs and programs with dependent types, and proofs of mathematical propositions • Works remarkably well on these programs • The author does not explicitly claim that undecidability is not a problem in practice Type Refinements for Programming Languages