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

Record updates #2263

Merged
merged 18 commits into from
Aug 7, 2023
Merged

Record updates #2263

merged 18 commits into from
Aug 7, 2023

Conversation

janmasrovira
Copy link
Collaborator

@janmasrovira janmasrovira commented Jul 27, 2023

This pr introduces syntax for convenient record updates.
Example:

type Triple (A B C : Type) :=
  | mkTriple {
      fst : A;
      snd : B;
      thd : C;
    };

main : Triple Nat Nat Nat;
main :=
  let
    p : Triple Nat Nat Nat := mkTriple 2 2 2;
    p' :
      Triple Nat Nat Nat :=
        p @Triple{
          fst := fst + 1;
          snd := snd * 3
        };
    f : Triple Nat Nat Nat -> Triple Nat Nat Nat := (@Triple{fst := fst * 10});
  in f p';

We write @InductiveType{..} to update the contents of a record. The @ is used for parsing. The InductiveType symbol indicates the type of the record update. Inside the braces we have a list of fieldName := newValue items separated by semicolon. The fieldName is bound in newValue with the old value of the field. Thus, we can write something like p @Triple{fst := fst + 1;}.

Record updates X@{..} are parsed as postfix operators with higher priority than application, so f x y @X{q := 1} is equivalent to f x (y @X{q := 1}).

It is possible the use a record update with no argument by wrapping the update in parentheses. See f in the above example.

@janmasrovira janmasrovira added enhancement New feature or request syntax labels Jul 27, 2023
@janmasrovira janmasrovira self-assigned this Jul 27, 2023
@janmasrovira janmasrovira marked this pull request as ready for review July 31, 2023 14:36
@paulcadman paulcadman added this to the 0.4.3 milestone Aug 1, 2023
@@ -2,21 +2,15 @@ module Juvix.Data.Fixity where

import Juvix.Prelude.Base

-- | Note that the order of the constructors is important due to the `Ord`
-- instance.
-- TODO should we rename PrecMinusOmega to PrecApp, PrecMinusOmega1 to PrecUpdate, and PrecOmega to PrecFunction/Arrow?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the renaming would be a good idea. Do we use these precedences for anything other than application, update and arrow?

Copy link
Collaborator Author

@janmasrovira janmasrovira Aug 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we use these precedences for anything other than application, update and arrow?

I think that is an exhaustive list, so no.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, makes sense, I can do the renaming there. Though not to disrupt the code too much I'm not getting rid of the old Fixity/Precedence framework, but translating the precedence graph to a linear precedence ordering at scoping.

Copy link
Collaborator

@lukaszcz lukaszcz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems on the right-hand side only the field being modified is available as an identifier denoting the old field. This is confusing, and leads to internal errors in some cases.

Type-checking

module records;

import Stdlib.Prelude open;

type Pair (A B : Type) := mkPair {pfst : A; psnd : B};

main : Pair Nat Nat;
main :=
     let p : Pair Nat Nat := mkPair 2 2
     in
     p @Pair{
       pfst := pfst + psnd
     }

results in:

/Users/heliax/Documents/progs/juvix/records.juvix:12:23-27: error:
Symbol not in scope: psnd
Perhaps you meant: snd
                   and

Type-checking:

module records;

import Stdlib.Prelude open;

type Pair (A B : Type) := mkPair {pfst : A; psnd : B};

main : Pair Nat Nat;
main :=
     let p : Pair Nat Nat := mkPair 2 2
     in
     p @Pair{
       pfst := pfst + 3;
       psnd := pfst;
     }

results in:

juvix: internal error: could not find var pfst@658
CallStack (from HasCallStack):
  error, called at src/Juvix/Prelude/Base.hs:375:9 in juvix-0.4.2-83yOy15uIzk3Wi2drQRaG6:Juvix.Prelude.Base
  error, called at src/Juvix/Compiler/Internal/Translation/FromInternal/Analysis/TypeChecking/Checker.hs:299:11 in juvix-0.4.2-83yOy15uIzk3Wi2drQRaG6:Juvix.Compiler.Internal.Translation.FromInternal.Analysis.TypeChecking.Checker

Type-checking:

module records;

import Stdlib.Prelude open;

type Pair (A B : Type) := mkPair {fst : A; snd : B};

main : Pair Nat Nat;
main :=
     let p : Pair Nat Nat := mkPair 2 2
     in
     p @Pair{
       fst := fst + snd;
     }

results in:

/Users/heliax/Documents/progs/juvix/records.juvix:12:21-24: error:
The expression snd {_} {_} has type:
  × _ _ → _
but is expected to have type:
  Nat

@janmasrovira
Copy link
Collaborator Author

This should be fixed now

@janmasrovira janmasrovira mentioned this pull request Aug 4, 2023
@lukaszcz lukaszcz self-requested a review August 4, 2023 15:40
@lukaszcz lukaszcz merged commit f7382ca into main Aug 7, 2023
4 checks passed
@lukaszcz lukaszcz deleted the record-updates branch August 7, 2023 10:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request syntax
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add syntax support for record updates
3 participants