Skip to content

feat!: saturated constructors#891

Closed
brprice wants to merge 195 commits intomainfrom
brprice/saturated-constructors
Closed

feat!: saturated constructors#891
brprice wants to merge 195 commits intomainfrom
brprice/saturated-constructors

Conversation

@brprice
Copy link
Copy Markdown
Contributor

@brprice brprice commented Feb 28, 2023

We enforce all (value) constructors must be fully-saturated. They will no longer carry their indices, i.e. we will have Just True rather than Just @Bool True. This implies that their typing rules must change, since we currently use these indices to infer types.

This change will introduce much symmetry between constructions and pattern matching of ADTs. It will also make some expressions much more concise (especially lists) due to not having type applications.

@brprice
Copy link
Copy Markdown
Contributor Author

brprice commented Feb 28, 2023

(I'll grab this comment as a todo list/current status, leaving the OP as an overview of the PR).

Status: nothing to see here code-wise, just opening a PR for a place to put some notes whilst this is in development. This PR is work towards #870

Note to self: some messy wip is at https://github.com/hackworthltd/primer/tree/brprice/wip/saturated-constructors

Todo (perhaps some of this should go in the FR #870):

  • Implementation:
    • I have done foldl' (TApp ()) t ts or foldlM tapp t ts a few times, when I should have used foldTApp or maybe mkTAppCon
  • Ensure that writing foo : ? = Just 5 works
  • Then ensure that refining the type hole works thus: foo : Maybe ? = Just 5 and then foo : Maybe Bool = Just {? 5 ?}
  • If a student is playing with match expressions to understand them and writes match (Just 5 : ?) with ..., we'll automatically insert the annotation (assuming that constructors are checkable only), but can we do better than an empty hole? (Perhaps in the future, as there are other places we may want to do the same -- does this change make anything along these lines harder?)
  • The easy rule is checkable-only:
      A ∋ t
----------------
Maybe A ∋ Just t

but it would be interesting to explore (for UX reasons) the synthesising rules

     ? ∋ t                   e ∈ S
----------------   or   ----------------
Just t ∈ Maybe ?        Just e ∈ Maybe S

both from a "hack this up for UX" and a "do it properly with decent metatheory" perspectives

  • There are some things to explore around extra actions to provide (and these will be easier to think about when we have a prototype of this feature!):
    • A way to insert an eta-expanded ctor: λx. Just x, λx xs. Cons x xs
    • But that does not help to insert λxs. Cons 1 xs
    • Perhaps a generic λ-lift a hole: ...?... ~> λx. ...x... would be a nice abstraction, then one can insert a constructor to get Cons ? ? and then λ-lift each argument.
  • What happens if one inserts a constructor inside a non-empty hole: this is a synthesisable position (why?), but constructors may only be checkable -- it would be bad UX to not offer the option there!

Roadmap:

  • (Option 1a) modify the API first (have a special case that detects constructor-headed spines -- this would not ensure fully-saturated-ness, but this is only a temporary stopping point)
    • mostly done -- currently this PR, but CI fails
  • Constructors can have (type and term) arguments, but not needed to be fully saturated, and still synthesisable. Expr = ... | Con Name [Type] [Expr], where Con "C" A x is equivalent to the tree (C @ A) $ x. Perhaps this can be added under a new name, with a pattern synonym for the old form, and this may help split the testsuite changes (although this is speculative).
  • Enforce constructors being fully-saturated (but still synthesisable) -- this is mostly a TC change, but will have knock-on effects on documentation and the testsuite. It will also require the "insert a bare constructor" action to be removed -- (possibly the action change can happen up front, before the core is changed?).
  • Enforce constructors being checkable, but still have type arguments. This is mostly a TC and Eval change, with knock-on effects on the testsuite and documentation. It will also require the "insert a saturated constructor" action to be offered in fewer places (although this too could happen up front).
  • Drop the type arguments Expr = ... | Con Name [Expr]. This should be a simple change, but with a lot of churn.
  • (Option 1b) modify the API last (render Cons x xs as a tree headed by APP -- we should have all the type information available from the TC, and can always put holes in the types if needed.)

@brprice brprice force-pushed the brprice/saturated-constructors branch from f208a4b to e159d1f Compare February 28, 2023 14:59
brprice added 14 commits March 7, 2023 18:59
Since the names are unique and the ordering information is exposed in
the input and second output, we can make the types reflect the fact that
the substitution does not need to be applied in any particular order.
(This will shortly work nicely with a forthcoming notion of simultaneous
substitution.)
This makes its telescopic nature clear at callsites.
Sometimes one needs capture-avoiding substitution of many variables
simultaneously. This is no harder than substituting one variable, so we
make this the primitive.
Everywhere we substitute multiple types we actually do not care whether
the substitution is telescopic or simultaneous. The only non-singleton
substitutions we use are from one of
- 'genInstApp's output (or the accumulated substitution in its helper 'reify')
- 'unify's output
These are both idempotent (i.e. the substituted types do not refer to
any of the names being substituted away), and thus both sorts of
substitution will return the same value. Thus we should use the more
efficient simultaneous substitution (which only has to traverse the tree
once).
…bstitution' into brprice/tmp/saturated-constructors-split-base
@brprice brprice force-pushed the brprice/saturated-constructors branch from 49168b5 to a321aac Compare March 9, 2023 11:46
@brprice brprice force-pushed the brprice/saturated-constructors branch from a321aac to da5b6a3 Compare March 9, 2023 12:06
brprice added 6 commits March 9, 2023 13:06
AIM: play around with conSat interactively and find what actions we
offer under them. It seem that we offer the expected set, which is good!

Now it actually creates a conSat. However, this only happens if we use
the ConstructSaturatedCon, not ConstructRefinedCon, and thus in an
openapi frontend only happens using the MakeConSat action in a position
with no type info (i.e. where the type is a hole). In particular, in the
program
  Cons @[?_1] [?_2, ?_3]
we have
- ?_2 : ?_1, so we would do a conSat here
- ?_3 : List ?_1, but we would not here (do a refine)
YES, it seems so (have rebased to not do API hack, and updated insert
sat con action. Interactively it seems that we offer expected stuff)

This reverts commit 05fc6ac.
These have to change together as EvalFull.8,9,prim_partial_map all compare map output with list_
@brprice brprice force-pushed the brprice/saturated-constructors branch from da5b6a3 to b415db7 Compare March 30, 2023 12:33
@brprice
Copy link
Copy Markdown
Contributor Author

brprice commented Apr 24, 2023

Note that a polished version of this PR has been opened in the following 5 PRs: #958 #959 #960 #961 #962

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FR: Saturated constructors

1 participant