types, types, types

Preview:

DESCRIPTION

In a weird parallel world where programming is based on type theory, every term has a type, if you declare it or not, every function has a type, and polymorphic functions can't know the type of their argument or see what's inside. Even if you don't use languages from that world, they can still be an inspiration.

Citation preview

types, types, types

types, types, typesIn a weird parallel world where programming is based on type theory, every term has a type, if you declare it or not, every function has a type, and polymorphic functions can't know the type of their argument or see what's inside.

Even if you don't use languages from that world, they can still be an inspiration.

goals

dissatisfied

excited

common language

outlinewarm-up. just ask the type inferencer

main A. type checking is lie detectionmain B. what is type theory anyway?

examples.

bonus. kinds

just ask thetype inferencer

just ask the type inferencerghci> :type 3 > 0

Hey type inferencer, I was just wondering:

4 What's the type of 3 > 0?

just ask the type inferencerghci> :type 3 > 0

3 > 0 :: Bool

The term 3 > 0 has the type Bool.

just ask the type inferencerghci> :type not

just ask the type inferencerghci> :type not

not :: Bool -> Bool

"not" is a function that takes a Bool to a Bool.

just ask the type inferencerghci> let f (x, y) = Trueghci> :type f

just ask the type inferencerghci> let f (x, y) = Trueghci> :type f

f :: (t, t1) -> Bool

f is a function that takes a pair ofany two types to a Bool.

someVar = f (True, "abc") -- True

just ask the type inferencerghci> let f x y = x == yghci> :type f

just ask the type inferencerghci> let f x y = x == yghci> :type f

f :: Eq a => a -> a -> Bool

f is a function that takes two of thesame type "a" to a Bool.

The type "a" must support equality.

just ask the type inferencerghci> :info Eq

class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool

("a" is a placeholder for a concrete type here.)

just ask the type inferencerghci> let f x = x * 2ghci> :type f

just ask the type inferencerghci> let f x = x * 2ghci> :type f

f :: Num a => a -> a

f is a function that takes a value of any type "a" to a value of the same type "a".

There must be an instance of Num for the type "a".

just ask the type inferencerghci> :info Num

class Num a where (+) :: a -> a -> a (*) :: a -> a -> a (-) :: a -> a -> a negate :: a -> a abs :: a -> a ...

just ask the type inferencerghci> let f x = x * 2ghci> f True

<interactive>:24:1: No instance for (Num Bool) arising from a use of `f' Possible fix: add an instance declaration for (Num Bool) In the expression: f True In an equation for `it': it = f True

ok

summary4 if you don't know the type, ask the type inferencer

4 functions have types

4 operations constrain types

main A

type checkingis lie detection

type checking is lie detectionintIdentity :: Int -> IntintIdentity x = x

type checking is lie detectionintIdentity :: Int -> IntintIdentity x = 42

But that's not an identity function! :(

how can we prevent ourselves from lying?

the function that…

type checking is lie detection-- intIdentity :: Int -> Intidentity :: a -> aidentity x = ???

type checking is lie detection-- intIdentity :: Int -> Intidentity :: a -> aidentity x = 42

type checking is lie detection-- intIdentity :: Int -> Intidentity :: a -> aidentity x = 42

That's a lie!The function must accept an argument of any type.

type checking is lie detection-- intIdentity :: Int -> Intidentity :: a -> aidentity x = 42

That's a lie!The function must accept an argument of any type.And it must return an argument of the same type.

type checking is lie detection-- intIdentity :: Int -> Intidentity :: a -> aidentity x = x

There is only one valid implementation*!

*that terminates and returns a value

parametricity

c++ templates and parametricitytemplate <typename t>t identity(t a) { return ???;}

c++ templates and parametricitytemplate <typename t>t identity(t a) { return 42;}

end of intermission

parametricityf :: [t] -> [t]

What can this function not do?

parametricityf :: [t] -> [t]

What can this function not do?

4 insert items

4 change values

parametricityf :: [t] -> [t]

So what can it do at all?

parametricityf :: [t] -> [t]

So what can it do at all?

4 rearrange list items

4 drop list items

parametricityHere is a valid implementation:

tail :: [t] -> [t]tail (x:xs) = xs -- non-emptytail _ = [] -- empty

-- example usage:-- tail [1,2,3] -- [2,3]-- tail "abc" -- "bc"-- tail [] -- []-- tail "" -- ""

parametricity / lie detectionf :: [t] -> t

parametricity / lie detectionhead :: [t] -> thead (x:_) = x

parametricity / lie detectionhead :: [t] -> thead (x:_) = x

Warning: Pattern match(es) are non-exhaustive In an equation for `head': Patterns not matched: []

parametricity / lie detectionhead :: [t] -> thead (x:_) = xhead [] = ???

4 the type [t] -> t is not inhabited

4 any function that claims to have that type is a lie

summary4 the less a function knows, the less it can do

4 if you can use a more abstract type, do it

4 not every type is inhabited

main B

what istype theory

anyway?

"type theory is the grand, unified theory of computation"— robert harper

type theory is a formal language that describeshow terms and typesrelate to each other

example: pairs4 how to combine two types into a pair type

4 how to construct values of that type

4 how to deconstruct pair values and types

4 how to simplify terms involving pairs

type theory: formation rulesA is a type <—— "assuming that…"B is a type——————————————— (∧F)A ∧ B is a type <—— "…this is a valid thing to write"

type theory: introduction rulesA is a typeB is a type——————————————— (∧F)A ∧ B is a type

x:A y:B——————————— (∧-Introduction)(x,y) : A∧B

type theory: elimination rulesA is a typeB is a type——————————————— (∧F)A ∧ B is a type

x:A y:B z : A∧B——————————— (∧I) ——————————— (∧E1)(x,y) : A∧B first z : A

type theory: elimination rulesA is a typeB is a type——————————————— (∧F)A ∧ B is a type

x:A y:B z : A∧B z : A∧B——————————— (∧I) ——————————— (∧E1) ———————————— (∧E2)(x,y) : A∧B first z : A second z : B

type theory: computation rulesfirst(x,y) —> x

second(x,y) —> y

(The left side reduces to the right side.)

4 formation rulesspecify syntax for types

4 introduction rulesspecify syntax for types and terms

4 elimination rulesare inverses of introduction rules (sort of)

4 computation rulesdescribe how terms can be simplified by evaluating them

next example: functions

type theory: implicationpropositional logic-------------------

A => B assuming that A implies BA and assuming there is a proof of A—————— B there is a proof of B

type theory: implicationpropositional logic type theory------------------- -----------

A => B f : (A => B)A x : A—————— ———————————— (=> Elimination) B (f x) : B

type theory: implicationHow do we construct a function?

type theory: implicationHow do we construct a function?

x:A . . given an object of type A, . an object of type B can be deduced . ——— y:B

type theory: implicationHow do we construct a function?

[x:A] [discharged assumption] . . given an object of type A, . an object of type B can be deduced . y:B———————————————— (=> Introduction) ??? : A => B

type theory: implicationHow do we construct a function?

[x:A] [discharged assumption] . . given an object of type A, . an object of type B can be deduced . y:B———————————————— (=>I)(λx. y) : A => B any function that takes an A and returns a B is a proof of A => B

type theory: implicationintroduction: elimination:

[x:A] f: A => B x:A . ——————————————— . (f x) : B . y:B———————————————— computation:(λx. y) : A => B beta reduction

a program is well-typedif it can be derived

using the rules

types as propositions

programs as proofs

"Curry–Howard correspondence"

what does that mean for some actual programs?

programs as proofsx :: Bool

programs as proofsx :: Boolx = False

programs as proofsx :: Boolx = False

(empty) (empty)——————————— ————————————True : bool False : bool

False is exactly one of the ways of how you construct a bool.

not bad

programs as proofsdata Color = Red | Green | Blue

c :: Color

programs as proofsdata Color = Red | Green | Blue

c :: Colorc = Blue

Blue is exactly one of the ways of how you construct a Color.

programs as proofsf :: (a -> b) -> a -> b

programs as proofsf :: (a -> b) -> a -> bf f1 x = ???

programs as proofsf :: (a -> b) -> a -> bf f1 x = f1 x

programs as proofsf :: (a -> b) -> a -> bf f1 x = f1 x

Why does a function of that type exist?

programs as proofsf :: (a -> b) -> a -> bf f1 x = f1 x

Why does a function of that type exist?

A => B A———————————— B

programs as proofsf :: (a -> b) -> a -> bf f1 x = f1 x

Why does a function of that type exist?

A => B [A]———————————— A => B

programs as proofsf :: (a -> b) -> (a -> b)f f1 x = f1 x

Why does a function of that type exist?

[A => B] [A]———————————————————— (sort of a silly proof)(A => B) => (A => B)

if it's provable, you can write a program

a well-typed program constitutes a proof

programs as proofsf :: (b -> c) -> (a -> b) -> a -> cf f1 f2 x = ???

programs as proofsf :: (b -> c) -> (a -> b) -> a -> cf f1 f2 x = ???

compare:

A => B B => C——————————————— transitivity A => C

programs as proofsf :: (b -> c) -> (a -> b) -> a -> cf f1 f2 x = f1 (f2 x)

compare:

A => B B => C——————————————— transitivity A => C

programs as proofsf :: (a -> b -> c) -> b -> a -> c

programs as proofsflip :: (a -> b -> c) -> b -> a -> cflip f y x = f x y

programs as proofsflip :: (a -> b -> c) -> b -> a -> cflip f y x = f x y

So what is flip a proof of?

programs as proofsflip :: (a -> b -> c) -> b -> a -> cflip f y x = f x y

So what is flip a proof of?

4 commutativity of implication

(A => (B => C)) <=> (B => (A => C))

but not every typehas a proof

programs as proofsf :: a -> bf x = ???

programs as proofsf :: a -> bf x = ???

If there is such a function, A => B must be provable.

?——————A => B

programs as proofsf :: a -> bf x = ???

If there is such a function, A => B must be provable.

Nope.——————A => B

programs as proofsf :: a -> bf x = ???

-- hypothetical usage examples:foo :: Int bar :: Boolfoo = f "hello" bar = f "hello"

programs as proofsf :: a -> bf x = ???

-- hypothetical usage examples:foo :: Int bar :: Boolfoo = f "hello" bar = f "hello"

You can't construct a value of an unknown type.

c++ templates and proofstemplate <typename t, typename t2>t2 f(t a, t2 b) { return ???;}

c++ templates and proofstemplate <typename t, typename t2>t2 f(t a, t2 b) { return "whatever";}

okay, so…

`typename t` does not mean `∀t`

end of intermission

summary4 type theory is a formal language that describes how

terms and types relate to each other

4 a program is a proof of its type

4 not every type has a proof (or is inhabited)

end of theory

so like, how would iwrite a head function

if i needed to?

3 options

option 1: more explicit input typetype NonEmptyList a = (a, [a])

option 1: more explicit input typetype NonEmptyList a = (a, [a])

head :: NonEmptyList a -> ahead (x, _) = x

option 2: more explicit output type-- head :: [a] -> ??head (x:_) = ThereIsTotallyAn x

option 2: more explicit output type-- head :: [a] -> ??head (x:_) = ThereIsTotallyAn xhead [] = NopeNothingNada

option 2: more explicit output typehead :: [a] -> MaybeAn ahead (x:_) = ThereIsTotallyAn xhead [] = NopeNothingNada

option 2: more explicit output typehead :: [a] -> MaybeAn ahead (x:_) = ThereIsTotallyAn xhead [] = NopeNothingNada

data MaybeAn a = ThereIsTotallyAn a | NopeNothingNada

MaybeAn a may contain an a, but it is not an a itself.

option 2: more explicit output typehead :: [a] -> Maybe ahead (x:_) = Just xhead [] = Nothing

data Maybe a = Just a | Nothing

Maybe a may contain an a, but it is not an a itself.

option 3: length-aware list typedata TaggedList length a -- -- add here: constructors for -- empty and non-empty lists --

data Zero -- 0data Succ n -- 1, 2, 3, 4, 5, 6, …

head :: TaggedList (Succ n) a -> ahead (x : _) = x

option 3: length-aware list typedata TaggedList length a where Empty :: TaggedList Zero a (:.) :: a -- an item -> TaggedList length a -- a list -> TaggedList (Succ length) a -- a longer list

data Zero -- 0data Succ n -- 1, 2, 3, 4, 5, 6, …

head :: TaggedList (Succ n) a -> ahead (x :. _) = x

wow

let's do somestatic duck-typing!

duck —> type# THIS IS PYTHON

def foo(x): return x * 2

print foo(3) # 6print foo("hi") # "hihi"

duck —> typefoo x = x * 2

main = do print (foo 3) -- 6

  ghci> :type foofoo :: Num a => a -> a

duck —> typefoo x = x * 2

main = do print (foo 3) print (foo "hi")

No instance for (Num [Char]) arising from a use of `foo'Possible fix: add an instance declaration for (Num [Char])In the first argument of `print', namely `(foo "hi")'In a stmt of a 'do' block: print (foo "hi")

duck —> typeclass Mul a where (*) :: a -> Int -> a

(a can be any concrete type)

duck —> typeclass Mul a where (*) :: a -> Int -> a

instance Mul Int where x * y = x Builtin.* y

instance Mul String where x * 1 = x x * n | n <= 0 = "" | n > 0 = x ++ x * (n - 1)

duck —> typemain = do print (foo 3::Int) -- 6 print (foo "hi") -- "hihi"

Boom. Done. Works.

bonus:

kinds

kindsThe comma in (Bool, Int) is a type-forming operator!

ghci> :kind (,)(,) :: * -> * -> *

kindsThe comma in (Bool, Int) is a type-forming operator!

ghci> :kind (,)(,) :: * -> * -> *

ghci> :kind (,) Bool(,) Bool :: * -> *

kindsThe comma in (Bool, Int) is a type-forming operator!

ghci> :kind (,)(,) :: * -> * -> *

ghci> :kind (,) Bool(,) Bool :: * -> *

ghci> :kind (,) Bool Int(,) Bool Int :: *

kindsghci> :kind [Int][] :: *

ghci> :kind [][] :: * -> *

alright

Reading recommendation4 TTFP — Type Theory and Functional Programming

fin

questions

questions

appendix

nested listsvar nestedList = [ 1 , 2 , [ 3 , [ 4, 5 ] ] ];

nested listsdata NestedList a = Atom a | Nest [NestedList a]

nestedList :: NestedList IntnestedList = Nest [ Atom 1 , Atom 2 , Nest [ Atom 3 , Nest [ Atom 4 , Atom 5 ] ] ]

Recommended