Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add record declaration syntax support #1641

Closed
jonaprieto opened this issue Nov 22, 2022 · 11 comments · Fixed by #2254
Closed

Add record declaration syntax support #1641

jonaprieto opened this issue Nov 22, 2022 · 11 comments · Fixed by #2254
Assignees
Milestone

Comments

@jonaprieto
Copy link
Collaborator

Example:

type A (B : Type) :=
  constructor1 {
    cfield1 : X1;
    cfield2 : X2;
  }
 | constructor2 {
    cfield3 : Y1;
 };
@jonaprieto jonaprieto added this to the 0.2.8 milestone Nov 22, 2022
@jonaprieto jonaprieto modified the milestones: 0.2.8, 0.2.9 Dec 20, 2022
@jonaprieto jonaprieto modified the milestones: 0.2.9, 0.3 Jan 19, 2023
@lukaszcz lukaszcz modified the milestones: 0.3, 0.5 Jan 24, 2023
@lukaszcz
Copy link
Collaborator

lukaszcz commented May 26, 2023

After implementing

we might not need or want a separate syntax for record declarations. With the proposed syntax for named arguments a record can be defined as:

type R :=
  Rctr : (cfield1 : X1) -> (cfield2 : X2) -> R;

If there is only one constructor, accessor functions can be automatically generated, maybe with an additional specifier like

record 
type R := 
  Rctr : (cfield1 : X1) -> (cfield2 : X2) -> R;

@lukaszcz
Copy link
Collaborator

lukaszcz commented May 26, 2023

But perhaps the named argument syntax becomes inconvenient with a large number of fields. So we may actually want the proposed syntactic sugar:

record
type R := Rctr { 
  cfield1 : X1;
  cfield2 : X2;
};

@lukaszcz
Copy link
Collaborator

I actually think this is much more readable:

trait
type Encoding (A : Type) := MkEncoding {
  encode : A -> Field; 
  decode : Field -> A;
};

than this:

trait
type Encoding (A : Type) :=
  MkEncoding : 
     (encode : A -> Field) -> 
     (decode : Field -> A) ->
     Encoding A;

@janmasrovira
Copy link
Collaborator

janmasrovira commented May 29, 2023

I agree with your points.

A couple of extra comments:

  1. The record keyword is not neccesary for parsing, we could simply disambiguate based on what's written. The problem then becomes that we don't know if we should generate field accessors or not. But I would say that it is ok to always generate them if there is a single constructor. If we did this, we don't need to record keyword at all.
  2. I think it'd be more consistent to use parentheses instead of braces after the constructor name. That way, we would respect the existing juvix convention to use braces for implicit arguments.

@lukaszcz
Copy link
Collaborator

  1. I think it'd be more consistent to use parentheses instead of braces after the constructor name. That way, we would respect the existing juvix convention to use braces for implicit arguments.

We use braces often for blocks of declarations, e.g., in lets. The fields of a constructor are a bit like such a block of signature declarations. Maybe we could use with here to indicate that we're starting a block of signatures (and to keep consistent with the syntax for updating/creating records)?

trait
type Encoding (A : Type) := MkEncoding with {
  encode : A -> Field; 
  decode : Field -> A;
};

@janmasrovira
Copy link
Collaborator

we are not using braces in lets. What blocks of declarations are you referring to?

@janmasrovira
Copy link
Collaborator

I wouldn't strongly oppose to braces however. I think they have a big pro, which is that they are often used for record-like structures in other languages

@lukaszcz
Copy link
Collaborator

No? Damn, I'm not keeping up with the syntax.

@lukaszcz
Copy link
Collaborator

I think I got confused with Core syntax.

But we're using braces in the lambdas, and that's a bit like introducing a block of clause definitions (but the analogy is weaker here).

@lukaszcz
Copy link
Collaborator

Braces seem nicer because multi-line parentheses look kind of weird. The parenthesisation is also easier to track visually if you follow the convention:

  • paretheses for small blocks (like application in expressions)
  • braces for (potentially) big blocks (like lambdas or record declaration/update)

@janmasrovira
Copy link
Collaborator

agreed

@paulcadman paulcadman modified the milestones: 0.4.1, 0.4.2 Jun 23, 2023
@lukaszcz lukaszcz modified the milestones: 0.4.2, 0.5 Jun 27, 2023
@janmasrovira janmasrovira self-assigned this Jul 10, 2023
@janmasrovira janmasrovira linked a pull request Jul 17, 2023 that will close this issue
lukaszcz pushed a commit that referenced this issue Jul 24, 2023
- Closes #1641 

This pr adds the option to declare constructors with fields. E.g.
```
type Pair (A B : Type) :=
  | mkPair {
      fst : A;
      snd : B
    };
```
Which is desugared to
```
type Pair (A B : Type) :=
  | mkPair :  (fst : A) -> (snd : B) -> Pair A B;
```
making it possible to write ` mkPair (fst := 1; snd := 2)`.


Mutli-constructor types are also allowed to have fields.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants