• No results found

Synthesis in ML syn

In document Program Synthesis With Types (Page 80-84)

5.2 A Functional Synthesis Programming Language

5.2.2 Synthesis in ML syn

Like λ→syn, we simply adapt the internal language typing judgment to perform synthesis by making the type of the judgment an input and the term an output as shown in Figure 5.6. With the irefine rules, we proceed by the shape of the goal type, synthesizing an introduction form I along with refining the examples

proj(X) = σi 7→χ1ii<n, . . .,σi 7→χkii<n whereX=σi 7→ C(χ1i, . . .,χki) i<n apply(f,x,σ7→ p f) = [p f/f][vi/x]σ 7→χi i<m wherep f =vi ⇒χii<m distribute(Σ,T,X,E) = (p1,X10), . . .,(pm,X0m) where ctors(Σ,T) = C1, . . .,Cm ∀i ∈ 1, . . .,n.pi =pattern(Σ,Ci) ∀i ∈ 1, . . .,n.X0i = [σ0σ7→ χ | σ7→ χ∈ X,σ(E) −→∗ Ci(χ1, . . .,χk), vbinders(pi,χ1, . . .,χk) = σ0] ctors(Σ,T) =C1, . . .,Cn where∀i ∈1, . . .,n.Ci : τ1∗. . .∗τk →T ∈ Σ pattern(Σ,C) =C(x1, . . .,xk) whereC : τ1∗. . .∗τk → T∈ Σ vbinders(p,e1, . . .,ek) = [e1/x1]. . .[ek/xk] wherep =C(x1, . . .,xk)

X. As with our presentation of λ→syn, we make this transformation explicit by delegating all of this additional example refinement behavior to meta-functions—

proj, apply, and distribute for constructors (irefine-base), functions (irefine- arr), and matches (irefine-match), respectively. The definition of these meta- functions are found in Figure 5.7.

Constructor synthesis generalizes both product and sum synthesis fromλ→syn. Whereas products only have two components inλ→syn, constructors have arbitrary, finite arity in MLsyn. And whereas sums only have two “tags”, inl and inr, con- structors have an arbitrary, finite amount of tags as dictated by Σ. At base type, we are free to I-refine a particular constructor C with irefine-baseif all the ex- amples share the same head constructorC. To synthesize theith argument of the constructor expression, we extract theith argument of each of the examples and use those—along with their respective environments—as our example values. For example, if we had the following collection of example worlds:

X =σ17→ C(χ11,χ12,χ13), σ27→ C(χ21,χ22,χ23).

Then irefine-base would split the examples into three collections of example worlds,

X1 =σ17→ χ11,σ27→ χ21 X2 =σ17→ χ12,σ27→ χ22 X3 =σ17→ χ13,σ27→ χ23,

which would be used to synthesize the arguments I1, I2, and I3toC, respectively. Synthesizing at arrow type is comparatively straightforward. In fact, the irefine-arr rule is almost identical to its λ

syn variant. The only difference is that withfix, we must create a binding for f, the function that we are currently defining or synthesizing. The binding has the goal type,τ1τ2, and as mentioned previously, we use the example itself—a partial function—as its value.

Note that X is a collection of example worlds where each example world has the form σ 7→ χ. Because of this, we may be refining several example worlds when applying irefine-arr, each of which contains its own partial function value. In λ→syn, refining a single example world versus multiple example worlds using

irefine-arr produced the same set of example values and bindings; only the original environments differed. Assuming that the initial environments paired with the example worlds are the same, then the two situations were equivalent.

worlds from Section 2.3.4:

X=σ1 7→ ρ1,σ2 7→ρ2 ρ1=v1 ⇒χ1 | v2⇒ χ2

ρ2=v3 ⇒χ3 | v4⇒ χ4 | v5 ⇒χ5.

Applying irefine-arr in MLsyn produces the following collection of example worlds:

X0 = [ρ1/f][v1/x]σ17→ χ1,[ρ1/f][v2/x]σ1 7→χ2

[ρ2/f][v3/x]σ27→ χ3,[ρ2/f][v4/x]σ2 7→χ4,[ρ2/f][v5/x]σ27→ χ5 Even if σ1 and σ2 are identical, f is bound to either ρ1 or ρ2 When evaluating applications to f in these example worlds, we will get different results asρ1and ρ2 are different partial functions. In particular, we will likely encounterNoMatch exceptions when evaluating one partial function but not the other because they will likely have distinct branches.

In contrast, if we included all the input/output examples in a single partial function:

X =σ7→ ρ

ρ=v1 ⇒χ1 | v2 ⇒χ2

v3 ⇒χ3 | v4 ⇒χ4 | v5⇒χ5. then applyproduces the following example worlds:

X0 = [ρ/f][v1/x]σ7→ χ1,[ρ/f][v2/x]σ7→ χ2

[ρ/f][v3/x]σ7→ χ3,[ρ/f][v4/x]σ7→ χ4,[ρ/f][v5/x]σ 7→ χ5

where each example world has all of the input/output examples available in the value of f.

Finally, irefine-match generalizes the synthesis of sums to data types with an arbitrary number of constructors of arbitrary arity. Like λsyn,irefine-match proceeds in three steps:

1. Guess a value of sum type to pattern match against.

2. Distribute the example worlds among the branches of the pattern match. 3. Recursively synthesize the branches of the pattern match.

The distributetakes care of the critical second step, creating m sets of example worlds X1, . . .,Xm corresponding to thempossible constructors of the data type. It proceeds by evaluating the scrutinee, E, within each example world of X and

sends that example world to the branch corresponding to the constructor that E evaluates to. Along the way, it binds the appropriate variables and constructor argument values for that branch.

As a concrete example, consider a definition of abooldata type with construc- tors trueandfalse. That is,

Σ =true :bool,false: bool. Then, if we have the following example worlds,

X= [true/b] 7→false,[false/b] 7→true,

applyingirefine-matchwithb as the scrutinee results in the following two sets of example worlds

X1=[true/b] 7→false

X2=[false/b]7→ true

where X1 are the examples for the true branch of the pattern match (because b evaluates to truein those example worlds) and X2 are the examples for the false branch of the pattern match (becauseb evaluates tofalse).

In document Program Synthesis With Types (Page 80-84)