Skip to content

refactor: Row parsing#116

Merged
croyzor merged 16 commits into
mainfrom
cr/refactor/row-parsing
May 29, 2026
Merged

refactor: Row parsing#116
croyzor merged 16 commits into
mainfrom
cr/refactor/row-parsing

Conversation

@croyzor

@croyzor croyzor commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

Redo the way we represent rows in syntax.

  1. We now represent rows for function types and annotations in Term as TypeRowElem ty (= Named String ty | Anon ty) rather than adding dummy names when desugaring
  2. Refactor the Flat syntax so that it doesn't mix in any Raw terms to represent types in rows

Now, Brat.Syntax.Raw only really does some disambiguation between variables and constructors, and we should soon be able to get rid of it altogether!

@croyzor croyzor requested a review from acl-cqc April 28, 2026 08:35

@acl-cqc acl-cqc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes! This looks fab, thank you 👍 😄. I don't think any comments are big except possibly in Elaborator.hs. Do you object to CType' or WC being functors? I could do that myself if you like the idea.

For awhile I thought this was keeping the named/anonymous distinction into the graph, something I tried once but couldn't get through, but now I realize this is a different change, albeit probably a big step towards the former. Love it!

Maybe edit the description where you say in Core to "in Term" or something that is more clearly still talking about parsing not the brat graph. (I guess writing Brat.Syntax.Core would also make that clear)

Comment thread brat/Brat/Checker/Helpers.hs Outdated
Comment thread brat/Brat/Syntax/Common.hs Outdated
Comment thread brat/Brat/Syntax/Concrete.hs
Comment thread brat/Brat/Syntax/Core.hs
| PApp
deriving (Bounded, Enum, Eq, Ord, Show)

data TypeAliasF tm = TypeAlias FC QualName [(PortName,TypeKind)] tm deriving Show

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What's the F? that it has an FC in it? I'd be tempted to call it TypeAliasFC if you think it's important to say that, again not perfect I admit

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The F is for "Functor", to say that this is the generic definition, but I guess it'd be more consistent to call it TypeAlias'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ah ok, alright then. Ah yes I see it's only moved anyway. Might you deriving Functor then?

Comment thread brat/Brat/Unelaborator.hs Outdated
unelab _ _ (tm ::: outs) = FAnnotation (unelab Chky Nouny <$> tm) (toRawRo outs)
unelab _ _ (tm ::: outs) = FAnnotation (unelab Chky Nouny <$> tm) (f outs)
where
f :: [TypeRowElem (KindOr (Term Chk Noun))] -> [TypeRowElem (WC (KindOr Flat))]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: this might be slightly easier to read as f :: (KindOr (Term Chk Noun)) -> WC (KindOr Flat) and put the outer two fmaps at the callsite

The outermost fmap is just over the list, so that could even just be map, too

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ah, actually this is just the same as unelabRo below, so just use that


Internal error: Expected empty unders after abstract, got:
(b1 :: Int)
(_1 :: Int)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes!!! That's much more sensible!!!

(Just to check - is it even possible to call something _1 and get this message yourself? We should choose the synthetic _ prefix so that it isn't...e.g. consider '0)

^^^^^^^^^

Port a1 is ambiguous in (a1 :: Nat), (a1 :: Nat)
Port not found: a1 in (_0 :: Nat, _0 :: Nat)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yay! :).

Can we try a similar test case where you explicitly pull _0 and see that that doesn't work (the element is anonymous, not named; the synthetic _ is only for printing/displaying, not pulling)?

@croyzor croyzor May 1, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch! The idea is that _0 isn't a valid user-supplied name for a port, but because of this it's not in our grammar for port pulling either, I'll add it back in.

I think the grammar for ports is [a-zA-Z][0-9a-zA-Z]*, so we could make the automatically inferred ports just 0,1,2...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done in 977b810

^^^^^^^^^^^

Type error: Expected a (kernel) function or vector of functions, got { (a1 :: Bool) -> (a1 :: { (a1 :: Qubit) -o (a1 :: Qubit) }) }
Type error: Expected a (kernel) function or vector of functions, got { (_0 :: Bool) -> (_1 :: { (_0 :: Qubit) -o (_0 :: Qubit) }) }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hmmmm ok. So it would actually be a different change (but still good as a later PR I guess) to carry this on through into the later stages of the compiler, changing NamedPort to distinguish between named/unnamed (which could be done in a few different ways). I might have another go at that....

Comment thread brat/test/golden/graph/addN2.brat.graph Outdated
(addN2.brat_globals_decl_13_addN,BratNode Id [("thunk",{ (inp :: Int) -> (out :: Int) })] [("thunk",{ (inp :: Int) -> (out :: Int) })])
(addN2.brat_globals_prim_2_N,BratNode (Prim ("","N")) [] [("value",Int)])
(addN2.brat_globals_prim_8_add,BratNode (Prim ("","add")) [] [("a1",{ (a :: Int), (b :: Int) -> (c :: Int) })])
(addN2.brat_globals_prim_8_add,BratNode (Prim ("","add")) [] [("_0",{ (a :: Int), (b :: Int) -> (c :: Int) })])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

So at some point we should try to make these anonymous too, I'm not quite sure even where we'd have to change, might be NamedPort (https://github.com/Quantinuum/brat/pull/116/changes#r3173191053). Not for this PR, fine...

@croyzor croyzor requested a review from acl-cqc May 15, 2026 12:39

@acl-cqc acl-cqc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes! I would say drop the support for pulling by compiler-generated names and update the test but basically good to go. Great stuff, thanks 🏆

(I'm also a bit suspicious about that typeclass. I might see whether I can remove that before you get to merge this....)

| PApp
deriving (Bounded, Enum, Eq, Ord, Show)

data TypeAliasF tm = TypeAlias FC QualName [(PortName,TypeKind)] tm deriving Show

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ah ok, alright then. Ah yes I see it's only moved anyway. Might you deriving Functor then?

-> Checking (-- [(Int, Test)] -- too much too hugr too soon?
[(Src, PrimTest (BinderType m))]
,[(String, (Src, BinderType m))] -- Remember the names given by programmers
,Solution m -- Remember the names given by programmers

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You might wanna put this comment by the definition of solution, or at least, put something there explaining what Solution is. Whether you then still need this comment here I don't mind.

@@ -59,7 +61,7 @@ solve :: forall m. Modey m
-> Problem
-> Checking (-- [(Int, Test)] -- too much too hugr too soon?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Drop this commented-out bit while you're here?

showSig :: (Show ty) => [TypeRowElem ty] -> String
showSig xs = parens $ intercalate ", " (showElem <$> xs)
where
parens x = '(':x ++ ")"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

make parens a toplevel? We have an export list here so it'd be private, which is fine

= intercalate ", " [ '(':p ++ " :: " ++ show ty ++ ")"
| (p, ty) <- x:xs]
showSig :: (Show ty) => [TypeRowElem ty] -> String
showSig xs = parens $ intercalate ", " (showElem <$> xs)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice :)

Comment thread brat/Brat/Checker.hs Outdated
Comment thread brat/Brat/Elaborator.hs
{ fnName = fnName d
, fnLoc = fnLoc d
, fnSig = fnSig d
, fnSig = fmap unWC <$> sig -- sus

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should the comment go on RawFuncDecl that it's fnSig does not include a WC and should?

Comment thread brat/Brat/Parser.hs Outdated
list2Cons _ = customFailure (Custom "Internal error list2Cons")

portPull = port <* match PortColon
portPull = (try port <|> (fmap show <$> number)) <* match PortColon

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I actually think you should not be able to portPull something using a compiler-generated name. Only using a name you specifically declared yourself. (I think you may have done this in response to an earlier comment by me that I should have phrased differently).

Reasoning: this makes the compiler's name-generation process part of the source code standard.

Comment thread brat/Brat/Parser.hs
nDecl = match TypeColon >> flatIOWithSpanFC

vDecl :: Parser (WC [FlatIO])
vDecl = functionSignature <&> (\(WC fc ty) -> WC fc [Named "thunk" (WC fc (Right ty))])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ok so this adds an extra WC compared to what we were doing before. Might this justify stripping out a level of WC when making a Decl fnSig (which you called sus earlier )?

Comment thread brat/Brat/Unelaborator.hs
unelab _ _ (Con c args) = FCon c (unelab Chky Nouny <$> args)
unelab _ _ (C (ss :-> ts)) = FFn (toRawRo ss :-> toRawRo ts)
unelab _ _ (K cty) = FKernel $ fmap (\(p, ty) -> Named p (toRaw ty)) cty
unelab _ _ (C (ss :-> ts)) = FFn ((unelabRo ss)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
unelab _ _ (C (ss :-> ts)) = FFn ((unelabRo ss)
unelab _ _ (C cty) = FFn (fmap unelabRo cty)

CTy may not be a Functor but this is non-Hasochistic CType' which is.

@acl-cqc

acl-cqc commented May 15, 2026

Copy link
Copy Markdown
Collaborator

(I'm also a bit suspicious about that typeclass. I might see whether I can remove that before you get to merge this....)

Done, I admit there was a little repetition but mostly type signatures and I was able to use FlatIO instead of something much longer for one case so I think that was good. Also generalized elabSig and it's counterpart elabIO over Traversable allowing to use in elaborate' for FFn and FKernel also.

Can you please find a better name for elaborateKindOrFlat though - is it somethitng like elaborateBratType ? :)

@croyzor croyzor merged commit d16cefc into main May 29, 2026
1 check passed
@croyzor croyzor deleted the cr/refactor/row-parsing branch May 29, 2026 11:07
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.

2 participants