generating programs from typesnpolikarpova/talks/lambda-days-2021.pdfmov [eax + info], ebx mov dword...
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