generating programs from typesnpolikarpova/talks/lambda-days-2021.pdfmov [eax + info], ebx mov dword...

Post on 25-Mar-2021

5 views 0 download

Transcript of generating programs from typesnpolikarpova/talks/lambda-days-2021.pdfmov [eax + info], ebx mov dword...

generating programs from types

Nadia Polikarpova

lambdaD A λ S

2

goal: automate programming

3

append:push ebpmov ebp, esppush eaxpush ebxpush lencall mallocmov ebx, [ebp + 12]mov [eax + info], ebxmov dword [eax + next], 0mov ebx, [ebp + 8]cmp dword [ebx], 0je null_pointermov ebx, [ebx]

next_element:cmp dword [ebx + next], 0je found_lastmov ebx, [ebx + next]jmp next_element

found_last:push eaxpush addMescall putsadd esp, 4pop eaxmov [ebx + next], eax

go_out:pop ebxpop eaxmov esp, ebppop ebpret 8

null_pointer:push eaxpush nullMescall putsadd esp, 4pop eaxmov [ebx], eaxjmp go_out

Assembly

3

void insert(node *xs, int x) {node *new;node *temp;node *prev;

new = (node *)malloc(sizeof(node)); if(new == NULL) {printf("Insufficient memory.");return;

} new->val = x;new->next = NULL;if (xs == NULL) {xs = new;

} else if(x < xs->val) {new->next = xs;xs = new;

} else { prev = xs;temp = xs->next;while(temp != NULL && x > temp->val) {prev = temp;temp = temp->next;

}if(temp == NULL) {prev->next = new;

} else {new->next = temp;prev->next = new;

}}

}

append:push ebpmov ebp, esppush eaxpush ebxpush lencall mallocmov ebx, [ebp + 12]mov [eax + info], ebxmov dword [eax + next], 0mov ebx, [ebp + 8]cmp dword [ebx], 0je null_pointermov ebx, [ebx]

next_element:cmp dword [ebx + next], 0je found_lastmov ebx, [ebx + next]jmp next_element

found_last:push eaxpush addMescall putsadd esp, 4pop eaxmov [ebx + next], eax

go_out:pop ebxpop eaxmov esp, ebppop ebpret 8

null_pointer:push eaxpush nullMescall putsadd esp, 4pop eaxmov [ebx], eaxjmp go_out

Assembly C

3

void insert(node *xs, int x) {node *new;node *temp;node *prev;

new = (node *)malloc(sizeof(node)); if(new == NULL) {printf("Insufficient memory.");return;

} new->val = x;new->next = NULL;if (xs == NULL) {xs = new;

} else if(x < xs->val) {new->next = xs;xs = new;

} else { prev = xs;temp = xs->next;while(temp != NULL && x > temp->val) {prev = temp;temp = temp->next;

}if(temp == NULL) {prev->next = new;

} else {new->next = temp;prev->next = new;

}}

}

insert x xs =match xs withNil → Cons x NilCons h t →if x ≤ hthen Cons x xselse Cons h (insert x t)

append:push ebpmov ebp, esppush eaxpush ebxpush lencall mallocmov ebx, [ebp + 12]mov [eax + info], ebxmov dword [eax + next], 0mov ebx, [ebp + 8]cmp dword [ebx], 0je null_pointermov ebx, [ebx]

next_element:cmp dword [ebx + next], 0je found_lastmov ebx, [ebx + next]jmp next_element

found_last:push eaxpush addMescall putsadd esp, 4pop eaxmov [ebx + next], eax

go_out:pop ebxpop eaxmov esp, ebppop ebpret 8

null_pointer:push eaxpush nullMescall putsadd esp, 4pop eaxmov [ebx], eaxjmp go_out

Assembly C Haskell

what’s next?

3

void insert(node *xs, int x) {node *new;node *temp;node *prev;

new = (node *)malloc(sizeof(node)); if(new == NULL) {printf("Insufficient memory.");return;

} new->val = x;new->next = NULL;if (xs == NULL) {xs = new;

} else if(x < xs->val) {new->next = xs;xs = new;

} else { prev = xs;temp = xs->next;while(temp != NULL && x > temp->val) {prev = temp;temp = temp->next;

}if(temp == NULL) {prev->next = new;

} else {new->next = temp;prev->next = new;

}}

}

insert x xs =match xs withNil → Cons x NilCons h t →if x ≤ hthen Cons x xselse Cons h (insert x t)

append:push ebpmov ebp, esppush eaxpush ebxpush lencall mallocmov ebx, [ebp + 12]mov [eax + info], ebxmov dword [eax + next], 0mov ebx, [ebp + 8]cmp dword [ebx], 0je null_pointermov ebx, [ebx]

next_element:cmp dword [ebx + next], 0je found_lastmov ebx, [ebx + next]jmp next_element

found_last:push eaxpush addMescall putsadd esp, 4pop eaxmov [ebx + next], eax

go_out:pop ebxpop eaxmov esp, ebppop ebpret 8

null_pointer:push eaxpush nullMescall putsadd esp, 4pop eaxmov [ebx], eaxjmp go_out

Assembly C Haskell

?future

4

How to split a string in Haskell?

How do I split a string on a custom separator? I want the following behavior:149

split ‘,’ “my,comma,separated,list” → [“my”, “comma”, “separated”, “list”]

4

How to split a string in Haskell?

How do I split a string on a custom separator? I want the following behavior:149

split ‘,’ “my,comma,separated,list” → [“my”, “comma”, “separated”, “list”]

split :: Char -> String -> [String] split c s = case dropWhile (== c) s of

"" -> [] s' -> w : split c s’’

where (w, s'') = break (== c) s'

157

You can implement it like this:

4

How to split a string in Haskell?

How do I split a string on a custom separator? I want the following behavior:149

split ‘,’ “my,comma,separated,list” → [“my”, “comma”, “separated”, “list”]

split :: Char -> String -> [String] split c s = case dropWhile (== c) s of

"" -> [] s' -> w : split c s’’

where (w, s'') = break (== c) s'

157

You can implement it like this:

program synthesis

5

programspecification

program synthesis

5

programsearch

program space

specification

program synthesis

5

programsearch

program space

? specification

program synthesis

6

programsearchspecification

program space

examplesassertions

natural language…

program synthesis

6

programsearchspecification

program space

examplesassertions

natural language…types!

the future is (almost) here

7

Char -> String -> [String] Search

the future is (almost) here

7

Char -> String -> [String] Search

split :: Char -> String -> [String]

ghc Util

the future is (almost) here

7

Char -> String -> [String] Search

split :: Char -> String -> [String]

ghc Util

8

simple types expressive types

8

simple types expressive types

more programmer-friendlymore ambiguous

8

simple types expressive types

more programmer-friendlymore ambiguous

less programmer-friendlyless ambiguous

8

simple types expressive types

this talk

9

simple types expressive types

part I: synquid

refinement types → recursive programs

this talk

9

simple types expressive types

part I: synquid

refinement types → recursive programs

part II: hoogle+

H+Haskell types →

function compositions

part I

10

synquid

refinement types → recursive programs

part I

10

synquid

refinement types → recursive programs

Polikarpova, Kuraj, Solar-Lezama: Program Synthesis from Polymorphic Refinement Types. [PLDI’16]

part I

10

synquid

refinement types → recursive programs

1. types as specifications

2. type-directed search

Polikarpova, Kuraj, Solar-Lezama: Program Synthesis from Polymorphic Refinement Types. [PLDI’16]

part I

11

synquid

refinement types → recursive programs

1. types as specifications

2. type-directed search

example: insert into a sorted list

12

example: insert into a sorted list

Input:

12

5x

example: insert into a sorted list

Input:

12

1 2 7 8

5

xs

x

example: insert into a sorted list

Input:

Output:

12

1 2 7 8

5

xs

x

1 2 7 85ys

insert in a functional language

13

insert x xs = 5

insert in a functional language

13

insert x xs =match xs with

5

insert in a functional language

13

insert x xs =match xs with

Nil →

Cons h t →

5

insert in a functional language

13

insert x xs =match xs with

Nil →Cons x Nil

Cons h t →5

5

insert in a functional language

13

insert x xs =match xs with

Nil →Cons x Nil

Cons h t →

5

insert in a functional language

13

insert x xs =match xs with

Nil →Cons x Nil

Cons h t →if x ≤ h

87 9

5

insert in a functional language

13

insert x xs =match xs with

Nil →Cons x Nil

Cons h t →if x ≤ h

then Cons x xs 875 9

5

insert in a functional language

13

insert x xs =match xs with

Nil →Cons x Nil

Cons h t →if x ≤ h

then Cons x xselse Cons h (insert x t)

5

7 82

insert in a functional language

13

insert x xs =match xs with

Nil →Cons x Nil

Cons h t →if x ≤ h

then Cons x xselse Cons h (insert x t)

specification code

our goal

14

match xs withNil → Cons x NilCons h t →if x ≤ hthen Cons x xselse Cons h (insert x t)

Nil, Cons, ≤, … program

space

specification code

our goal

14

match xs withNil → Cons x NilCons h t →if x ≤ hthen Cons x xselse Cons h (insert x t)

Nil, Cons, ≤, …

?

program space

types are specifications

15

types are specifications

15

insert :: a → List a → List a

types are specifications

15

insert :: a → List a → List a

types are specifications

15

insert :: a → List a → List a

specification

insert in synquid

16

a → List a→ List a

Nil, Cons, ≤, …

specification code

insert in synquid

16

a → List a→ List a

Nil, Cons, ≤, …

specification code

insert in synquid

16

a → List a→ List a

Nil, Cons, ≤, …

?

demo: insert

17

http://comcom.csail.mit.edu/demos/#1-insert

specification

insert in synquid

18

a → List a→ List a

Nil, Cons, ≤, …

specification code

insert in synquid

18

a → List a→ List a

Nil

Nil, Cons, ≤, …

specification code

insert in synquid

18

a → List a→ List a

Nil

Nil, Cons, ≤, …

specification code

insert in synquid

18

a → List a→ List a

Nil

Nil, Cons, ≤, …

power to the types!

specification for insert

19

specification for insert

19

Input:

x

specification for insert

19

Input:

x

xs: sorted list

specification for insert

19

Input:

x

xs: sorted list

Output:

ys: sorted list

specification for insert

19

Input:

x

xs: sorted list

Output:

ys: sorted list

elems ys = elems xs ∪ {x}

specification for insert

19

Input:

x

xs: sorted list

Output:

ys: sorted list

elems ys = elems xs ∪ {x}

can I write this as a type?

refinement types

20

{ v:Int | 0 ≤ v }

refinement types

20

{ v:Int | 0 ≤ v }

refinement

refinement types

20

{ v:Int | 0 ≤ v }

natural numbers

refinement types

20

{ v:Int | 0 ≤ v }List

lists of nats

data SList a where

refinement types: sorted lists

21

List a

data SList a whereNil :: SList a

refinement types: sorted lists

21

List aList a

data SList a whereNil :: SList aCons :: h:a →

t:SList {v:a | h ≤ v} →SList a

refinement types: sorted lists

21

List aList a

List aList a →

data SList a whereNil :: SList aCons :: h:a →

t:SList {v:a | h ≤ v} →SList a

refinement types: sorted lists

21

List a

List aList a →

data SList a whereNil :: SList aCons :: h:a →

t:SList {v:a | h ≤ v} →SList a

refinement types: sorted lists

21

7 82SList a →

data SList a whereNil :: SList aCons :: h:a →

t:SList {v:a | h ≤ v} →SList a

refinement types: sorted lists

21

7 82SList a →

data SList a whereNil :: SList aCons :: h:a →

t:SList {v:a | h ≤ v} →SList a

refinement types: sorted lists

21

7 82

data SList a whereNil :: SList aCons :: h:a →

t:SList {v:a | h ≤ v} →SList a

refinement types: sorted lists

21

7 82

all you need is one simple predicate!

insert :: x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

refinement type for insert

22

SList aList axs:List a

insert :: x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

refinement type for insert

22

SList aList a

insert :: x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

refinement type for insert

22

SList a

insert :: x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

refinement type for insert

22

insert in synquid

23

match xs withNil → Cons x NilCons h t →if x ≤ hthen Cons x xselse Cons h (insert x t)

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

specification code

demo: insert

24

http://comcom.csail.mit.edu/demos/#1-insert

part I

25

synquid

refinement types → recursive programs

1. types as specifications

2. type-directed search

?

how did this happen?

26

match xs withNil → Cons x NilCons h t →if x ≤ hthen Cons x xselse Cons h (insert x t)

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

specification code

synthesis as search

27

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

specification

synthesis as search

28

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

specification

synthesis as search

28

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

Nil, Cons, ≤, …

specification

components

synthesis as search

28

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

Nil, Cons, ≤, …

specification

components

code

synthesis as search

28

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

Nil, Cons, ≤, …

specification

components

code

synthesis as search

28

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

Nil, Cons, ≤, …

specification

components

code

synthesis as search

28

...

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

Nil, Cons, ≤, …

specification

components

code

synthesis as search

28

...

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

Nil, Cons, ≤, …

specification

components

code

synthesis as search

28

...

too many

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

Nil, Cons, ≤, …

specification

components

code

synthesis as search

28

...

too many270

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

Nil, Cons, ≤, …

specification

components

code

29

synthesis as search

29

synthesis as search

29

synthesis as search

29

synthesis as search

29

synthesis as search

29

synthesis as search

29

synthesis as search

29

key idea: reject hopeless programs early

synthesis as search

29

key idea: reject hopeless programs early

synthesis as search

(during construction)

rejecting hopeless programs

30

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

specification

rejecting hopeless programs

30

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

specification

previous work*: bottom-up type checking

*Rondon, Kawaguchi, Jhala: Liquid types. [PLDI 2008]

rejecting hopeless programs

31

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

specification

??

our work: top-down type checking

rejecting hopeless programs

31

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

specification

??

our work: top-down type checking

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

rejecting hopeless programs

32

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =

rejecting hopeless programs

32

??

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =

rejecting hopeless programs

32

??hopeless?

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =

rejecting hopeless programs

32

??

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

??

rejecting hopeless programs

32

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

??

rejecting hopeless programs

32

hopeless?

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

??

rejecting hopeless programs

32

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

rejecting hopeless programs

32

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

rejecting hopeless programs

32

hopeless?

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

rejecting hopeless programs

32

hopeless?hopeless:output must always contain x!

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

rejecting hopeless programs

32

250

hopeless?hopeless:output must always contain x!

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

top-down type checking

33

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

{v:SList a | elems v = elems xs ∪ {x}}

top-down type checking

33

insert x xs =match xs with

Nil → NilCons h t → ??

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

{v:SList a | elems v = elems xs ∪ {x}}

top-down type checking

33

insert x xs =match xs with

Nil → NilCons h t → ??

insert x xs =match xs with

Nil → NilCons h t → ??

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

{v:SList a | elems v = elems xs ∪ {x}}

top-down type checking

33

insert x xs =match xs with

Nil → NilCons h t → ??

insert x xs =match xs with

Nil → NilCons h t → ??

Constraints: ∀x: {} = {} ∪ {x}

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

{v:SList a | elems v = elems xs ∪ {x}}

top-down type checking

33

insert x xs =match xs with

Nil → NilCons h t → ??

insert x xs =match xs with

Nil → NilCons h t → ??

Constraints: ∀x: {} = {} ∪ {x}

x:a → xs:SList a →{v:SList a | elems v = elems xs ∪ {x}}

insert x xs =match xs with

Nil → NilCons h t → ??

{v:SList a | elems v = elems xs ∪ {x}}

top-down type checking

33

insert x xs =match xs with

Nil → NilCons h t → ??

insert x xs =match xs with

Nil → NilCons h t → ??

Constraints: ∀x: {} = {} ∪ {x}

specification code

insert in synquid

36

match xs withNil → Cons x NilCons h t →if x ≤ hthen Cons x xselse Cons h (insert x t)

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

specification code

insert in synquid

36

match xs withNil → Cons x NilCons h t →if x ≤ hthen Cons x xselse Cons h (insert x t)

insert :: x:a →xs:SList a →{v:SList a | elems v =elems xs ∪ {x}}

¬(a ⇒ b ∨ c)

case study: negation normal form

37

¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)

case study: negation normal form

37

1. only ¬, ∧, ∨

2. ¬ only at variables

¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)

case study: negation normal form

37

1. only ¬, ∧, ∨

2. ¬ only at variables

¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)

case study: negation normal form

37

1. only ¬, ∧, ∨

2. ¬ only at variables

¬(¬a ∨ (b ∨ c))⇒ def.

¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)

case study: negation normal form

37

1. only ¬, ∧, ∨

2. ¬ only at variables

¬(¬a ∨ (b ∨ c))

¬¬a ∧ ¬(b ∨ c)

⇒ def.

De Morgan

¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)

case study: negation normal form

37

1. only ¬, ∧, ∨

2. ¬ only at variables

¬(¬a ∨ (b ∨ c))

¬¬a ∧ ¬(b ∨ c)

a ∧ ¬(b ∨ c)

⇒ def.

De Morgan

double-neg

¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)¬(a ⇒ b ∨ c)

case study: negation normal form

37

a ∧ (¬b ∨ ¬c)

1. only ¬, ∧, ∨

2. ¬ only at variables

¬(¬a ∨ (b ∨ c))

¬¬a ∧ ¬(b ∨ c)

a ∧ ¬(b ∨ c)

⇒ def.

De Morgan

double-neg

De Morgan

nnf: data types

38

data Fml where

nnf: data types

38

data Fml whereVar :: String → Fml

nnf: data types

38

data Fml whereVar :: String → FmlNot :: Fml → Fml

nnf: data types

38

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → Fml

nnf: data types

38

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → Fml

nnf: data types

38

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

nnf: data types

38

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF where

nnf: data types

38

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNF

nnf: data types

38

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNF

negated?

nnf: data types

38

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNF

negated?

nnf: data types

38

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

negated?

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool where

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool whereVar v → env v

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool whereVar v → env vNot f → !(eval f)

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool whereVar v → env vNot f → !(eval f)And l r → eval l && eval r

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool whereVar v → env vNot f → !(eval f)And l r → eval l && eval rOr l r → eval l || eval r

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool whereVar v → env vNot f → !(eval f)And l r → eval l && eval rOr l r → eval l || eval rImp l r → eval l ==> eval r

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool whereVar v → env vNot f → !(eval f)And l r → eval l && eval rOr l r → eval l || eval rImp l r → eval l ==> eval r

measure nEval :: NNF → Bool where

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool whereVar v → env vNot f → !(eval f)And l r → eval l && eval rOr l r → eval l || eval rImp l r → eval l ==> eval r

measure nEval :: NNF → Bool whereNAtom neg v → if neg then env v

else !(env v)

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool whereVar v → env vNot f → !(eval f)And l r → eval l && eval rOr l r → eval l || eval rImp l r → eval l ==> eval r

measure nEval :: NNF → Bool whereNAtom neg v → if neg then env v

else !(env v)NAnd l r → nEval l && nEval r

nnf: specification

39

data Fml whereVar :: String → FmlNot :: Fml → FmlAnd :: Fml → Fml → FmlOr :: Fml → Fml → FmlImp :: Fml → Fml → Fml

data NNF whereNAtom :: String → Bool

→ NNFNAnd :: NNF → NNF → NNFNOr :: NNF → NNF → NNF

measure eval :: Fml → Bool whereVar v → env vNot f → !(eval f)And l r → eval l && eval rOr l r → eval l || eval rImp l r → eval l ==> eval r

measure nEval :: NNF → Bool whereNAtom neg v → if neg then env v

else !(env v)NAnd l r → nEval l && nEval rNOr l r → nEval l || nEval r

nnf: specification

40

nnf :: f:Fml → {v:NNF | nEval v = eval f}

nnf: synthesized code

41

nnf :: f:Fml → {v:NNF | nEval v = eval f}

nnf: synthesized code

41

nnf :: f:Fml → {v:NNF | nEval v = eval f}nnf p = match p with

BoolLiteral x2 → if x2then NOr (NAtom dummy x2) (NAtom dummy False)else NAnd (NAtom dummy x2) (NAtom dummy True)

Var x16 → NAtom x16 FalseNot x20 → match x20 withBoolLiteral x22 → if x22then nnf (BoolLiteral False)else nnf (BoolLiteral True)

Var x28 → NAtom x28 TrueNot x32 → nnf x32And x36 x37 → NOr (nnf (Not x36)) (nnf (Not x37))Or x46 x47 → NAnd (nnf (Not x46)) (nnf (Not x47))Implies x56 x57 → NAnd (nnf x56) (nnf (Not x57))

And x65 x66 → NAnd (nnf x65) (nnf x66)Or x73 x74 → NOr (nnf x73) (nnf x74)Imp x81 x82 → NOr (nnf x82) (nnf (Not x81))

nnf: synthesized code

41

nnf :: f:Fml → {v:NNF | nEval v = eval f}nnf p = match p with

BoolLiteral x2 → if x2then NOr (NAtom dummy x2) (NAtom dummy False)else NAnd (NAtom dummy x2) (NAtom dummy True)

Var x16 → NAtom x16 FalseNot x20 → match x20 withBoolLiteral x22 → if x22then nnf (BoolLiteral False)else nnf (BoolLiteral True)

Var x28 → NAtom x28 TrueNot x32 → nnf x32And x36 x37 → NOr (nnf (Not x36)) (nnf (Not x37))Or x46 x47 → NAnd (nnf (Not x46)) (nnf (Not x47))Implies x56 x57 → NAnd (nnf x56) (nnf (Not x57))

And x65 x66 → NAnd (nnf x65) (nnf x66)Or x73 x74 → NOr (nnf x73) (nnf x74)Imp x81 x82 → NOr (nnf x82) (nnf (Not x81)) ⇒ def.

nnf: synthesized code

41

nnf :: f:Fml → {v:NNF | nEval v = eval f}nnf p = match p with

BoolLiteral x2 → if x2then NOr (NAtom dummy x2) (NAtom dummy False)else NAnd (NAtom dummy x2) (NAtom dummy True)

Var x16 → NAtom x16 FalseNot x20 → match x20 withBoolLiteral x22 → if x22then nnf (BoolLiteral False)else nnf (BoolLiteral True)

Var x28 → NAtom x28 TrueNot x32 → nnf x32And x36 x37 → NOr (nnf (Not x36)) (nnf (Not x37))Or x46 x47 → NAnd (nnf (Not x46)) (nnf (Not x47))Implies x56 x57 → NAnd (nnf x56) (nnf (Not x57))

And x65 x66 → NAnd (nnf x65) (nnf x66)Or x73 x74 → NOr (nnf x73) (nnf x74)Imp x81 x82 → NOr (nnf x82) (nnf (Not x81)) ⇒ def.

double-neg

nnf: synthesized code

41

nnf :: f:Fml → {v:NNF | nEval v = eval f}nnf p = match p with

BoolLiteral x2 → if x2then NOr (NAtom dummy x2) (NAtom dummy False)else NAnd (NAtom dummy x2) (NAtom dummy True)

Var x16 → NAtom x16 FalseNot x20 → match x20 withBoolLiteral x22 → if x22then nnf (BoolLiteral False)else nnf (BoolLiteral True)

Var x28 → NAtom x28 TrueNot x32 → nnf x32And x36 x37 → NOr (nnf (Not x36)) (nnf (Not x37))Or x46 x47 → NAnd (nnf (Not x46)) (nnf (Not x47))Implies x56 x57 → NAnd (nnf x56) (nnf (Not x57))

And x65 x66 → NAnd (nnf x65) (nnf x66)Or x73 x74 → NOr (nnf x73) (nnf x74)Imp x81 x82 → NOr (nnf x82) (nnf (Not x81)) ⇒ def.

double-neg

De Morgan

this talk

42

simple types expressive types

part I: synquid

refinement types → recursive programs

part II: hoogle+

H+Haskell types →

function compositions

part II

43

hoogle+

Haskell types → function compositions

H+

synquid: limitation

44

programspecification

synquid: limitation

44

programspecification

part II

45

hoogle+

Haskell types → function compositions

H+Guo et al.: Program Synthesis by Type-Guided Abstraction Refinement [POPL’20]

1. overcoming ambiguity

2. helping beginners with types

James et al.: Digging for Fold: Synthesis-Aided API Discovery for Haskell [OOPSLA’20]

inspiration: hoogle

46

Char -> String -> [String] Search

split :: Char -> String -> [String]

ghc Util

inspiration: hoogle

46

Char -> String -> [String] Search

split :: Char -> String -> [String]

ghc Util

example: compress a list

Input:

47

1 1 2 1

example: compress a list

Input:

Output:

47

1 1 2 1

1 2 1

example: compress a list

Input:

Output:

47

1 1 2 1

1 2 1

1 1 2 1

group

example: compress a list

Input:

Output:

47

1 1 2 1

1 2 1

1 1 2 1

group

map head

compress: specification

48

compress :: Eq a => [a] → [a]

compress: specification

48

compress :: Eq a => [a] → [a]

hoogle+

49

programs

Haskell libraries

specification

H+ 1.2.3.4.

Eq a => [a] → [a]

hoogle+

49

programs

Haskell libraries

specification

H+ 1.2.3.4.

Eq a => [a] → [a]

hoogle+

49

programs

Haskell libraries

specification

H+ 1.2.3.4.

Eq a => [a] → [a]

hoogle+

49

programs

Haskell libraries

specification

H+ 1.2.3.4.

Eq a => [a] → [a]

hoogle+

50

Eq a => [a] → [a] SearchHoogλe+\xs -> concat (group xs)

\xs -> head (group xs)

\xs -> last (group xs)

\xs -> map head (group xs)

[0,1] -> [0,1][0,0] -> [0,0]

[0,1] -> [0][0,0] -> [0,0]

[0,1] -> [1][0,0] -> [0,0]

[0,1] -> [0,1][0,0] -> [0]

hoogle+

50

Eq a => [a] → [a] SearchHoogλe+\xs -> concat (group xs)

\xs -> head (group xs)

\xs -> last (group xs)

\xs -> map head (group xs)

[0,1] -> [0,1][0,0] -> [0,0]

[0,1] -> [0][0,0] -> [0,0]

[0,1] -> [1][0,0] -> [0,0]

[0,1] -> [0,1][0,0] -> [0]

part III

51

hoogle+

Haskell types → function compositions

H+ 1. overcoming ambiguity

2. helping beginners with types

too many irrelevant results

52

Eq a => [a] → [a] SearchHoogλe+

\xs -> []

\xs -> xs

\xs -> head []

\xs -> tail xs

too many irrelevant results

52

Eq a => [a] → [a] SearchHoogλe+

\xs -> []

\xs -> xs

\xs -> head []

\xs -> tail xs

always crashes!

too many irrelevant results

52

Eq a => [a] → [a] SearchHoogλe+

\xs -> []

\xs -> xs

\xs -> head []

\xs -> tail xs

ignores the argument!

always crashes!

too many irrelevant results

52

Eq a => [a] → [a] SearchHoogλe+

\xs -> []

\xs -> xs

\xs -> head []

\xs -> tail xs

ignores the argument!

always crashes!

ignores the type class!

ignores the type class!

too many irrelevant results

53

Eq a => [a] → [a] SearchHoogλe+

\xs -> head (group xs)

\xs -> init (head (group xs))

\xs -> tail (head (group xs))

too many irrelevant results

53

Eq a => [a] → [a] SearchHoogλe+

\xs -> head (group xs)

\xs -> init (head (group xs))

\xs -> tail (head (group xs)) duplicate!

test-based filtering

54

candidatessearchtype query

Eq a =>[a] → [a]

test-based filtering

54

candidatessearchtype query

Eq a =>[a] → [a]

results

QuickCheck / SmallCheck

test-based filtering

54

candidatessearchtype query

Eq a =>[a] → [a]

results

QuickCheck / SmallCheck

1. does it crash on all inputs?

test-based filtering

54

candidatessearchtype query

Eq a =>[a] → [a]

results

QuickCheck / SmallCheck

1. does it crash on all inputs?2. is the output always the same as another candidate?

test-based filtering

54

candidatessearchtype query

Eq a =>[a] → [a]

results

QuickCheck / SmallCheck

1. does it crash on all inputs?2. is the output always the same as another candidate?

3. does the output stay the same when changing an input?

comprehension

55

Eq a => [a] → [a] SearchHoogλe+

\xs -> concat (group xs)

\xs -> head (group xs)

\xs -> last (group xs)

\xs -> map head (group xs)

comprehension

55

Eq a => [a] → [a] SearchHoogλe+

\xs -> concat (group xs)

\xs -> head (group xs)

\xs -> last (group xs)

\xs -> map head (group xs)

how do I know what these

programs do?

test-based comprehension

56

Eq a => [a] → [a] SearchHoogλe+\xs -> concat (group xs)

\xs -> head (group xs)

\xs -> last (group xs)

\xs -> map head (group xs)

[0,1] -> [0,1][0,0] -> [0,0]

[0,1] -> [0][0,0] -> [0,0]

[0,1] -> [1][0,0] -> [0,0]

[0,1] -> [0,1][0,0] -> [0]

test-based comprehension

56

Eq a => [a] → [a] SearchHoogλe+\xs -> concat (group xs)

\xs -> head (group xs)

\xs -> last (group xs)

\xs -> map head (group xs)

[0,1] -> [0,1][0,0] -> [0,0]

[0,1] -> [0][0,0] -> [0,0]

[0,1] -> [1][0,0] -> [0,0]

[0,1] -> [0,1][0,0] -> [0]

part III

57

hoogle+

Haskell types → function compositions

H+ 1. overcoming ambiguity

2. helping beginners with types

Eq a => [a] → [a]

hoogle+

58

programsspecification

H+ 1.2.3.4.

Eq a => [a] → [a]

hoogle+

58

programsspecification

H+ 1.2.3.4.

can we infer type from tests?

59

programsspecification

H+ 1.2.3.4.

Eq a => [a] → [a]

[1,1,2,1] → [1,2,1]

“abba” → “aba”

types from tests

60

[1,1,2,1] → [1,2,1] “abba” → “aba”

types from tests

60

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

ghci ghci

types from tests

60

Ord a => [a] → [a]

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

ghci ghci

least common generalization

types from tests

60

Ord a => [a] → [a]

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

Eq a => [a] → [a]

ghci ghci

least common generalization

types from tests

60

Ord a => [a] → [a]

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

Eq a => [a] → [a]

[a] → [a]

ghci ghci

least common generalization

types from tests

60

Ord a => [a] → [a]

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

Eq a => [a] → [a]

[a] → [a]

a → [b] [a] → b

ghci ghci

least common generalization

[a] → [b]

more general types

types from tests

61

Ord a => [a] → [a]

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

Eq a => [a] → [a]

[a] → [a]

a → [b] [a] → b

[a] → [b]

types from tests

61

Ord a => [a] → [a]

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

Eq a => [a] → [a]

[a] → [a]

a → [b] [a] → b

[a] → [b]

generalizes over complex type

types from tests

61

Ord a => [a] → [a]

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

Eq a => [a] → [a]

[a] → [a]

[a] → [b]

types from tests

61

Ord a => [a] → [a]

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

Eq a => [a] → [a]

[a] → [a]

[a] → [b] unreachable type variable b

types from tests

61

Ord a => [a] → [a]

[1,1,2,1] → [1,2,1] “abba” → “aba”

[Int] → [Int] [Char] → [Char]

Eq a => [a] → [a]

[a] → [a]

types from tests

61

Ord a => [a] → [a]

Eq a => [a] → [a]

[a] → [a]

part II

62

hoogle+

Haskell types → function compositions

H+ user study

user study

30 participants

63

user study

30 participants

4 tasks

63

user study

30 participants

4 tasks

2 with Hoogle, then 2 with Hoolge+

63

results: completed tasks

64

29

44

0

15

30

45

60

Hoogle Hoogle+

results: completed tasks

64

29

44

0

15

30

45

60

Hoogle Hoogle+

51%more!

modes of specificationtype only

19%

type + test

39%

test only

42%

65

modes of specification: beginnerstype only

19% type + test

27%

test only

54%66

this talk

67

simple types expressive types

part I: synquid

refinement types → recursive programs

part II: hoogle+

H+Haskell types →

function compositions