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
Overloaded Quotation Brackets #246
Conversation
Thanks for writing this up! Since we have discussed it extensively already, needless to say I support the proposed changes. |
|
||
data Code m a = Code (m (TExp a)) | ||
|
||
instnace TypedQuote Code where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/instnace/instance/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks.
I still feel the Typed Template Haskell changes should be a separate proposal depending on the original. I agree that |
|
||
instnace TypedQuote Code where | ||
|
||
weaken :: Code WQ a -> WQ (TExp a) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WQ
is no longer in the proposal, want to replace with State NameSupply
or bind that as WQ
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
Example 1: Creating a partially static data type:: | ||
|
||
data Expr m a where | ||
Leaf :: Code m a -> Expr a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it be Leaf :: Code m a -> Expr m a
? Same goes for the other constructors, Int
and Add
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Thanks.
instance TypedQuote Expr where | ||
fromBracket = Leaf . Code | ||
|
||
expr = [|| 5 ||] `Add` [|| 10 ||] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Admittedly, I don't fully understand this use case. OK, now we have expr :: Quote m => Expr m Int
, how would one instantiate m
and make use of this expr
?
And why would one prefer it over this variant, where Expr
does not mention m
:
data Expr a where
Leaf :: TExp a -> Expr a
Int :: Int -> Expr Int
Add :: Expr Int -> Expr Int -> Expr Int
newtype ExprGen m a =
ExprGen (m (Expr a)) -- like Code for TExp
instance TypedQuote ExprGen where
fromBracket = ExprGen . fmap Leaf
add :: Applicative m => ExprGen m Int -> ExprGen m Int -> ExprGen m Int
add (ExprGen x) (ExprGen y) = ExprGen (liftA2 Add x y)
expr = [|| 5 ||] `add` [|| 10 ||]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That code also seems fine. I think you could choose to design it either way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, but then there's fmap
, so this class
class TypedQuote p where
fromBracket :: m (TExp a) -> p m a
must become
class TypedQuote p where
fromBracket :: Functor m => m (TExp a) -> p m a
Static pointers are mentioned for comparision, but the crucial difference is https://hackage.haskell.org/package/base/docs/GHC-StaticPtr.html#t:IsStatic supports the identity instance. If that is to be the inspiration, I rather make it more directly so: class IsExp p where
fromExp :: Exp -> p
instance IsExp Exp where
fromExp = id
class IsTExp p where
fromTExp :: TExp a -> p a
instance IsTExp TExp where
fromTExp = id @int-index's alternative code example (#246 (comment)) is changed to: data Expr a where
Leaf :: TExp a -> Expr a
Int :: Int -> Expr Int
Add :: Expr Int -> Expr Int -> Expr Int
instance IsTExp Expr where
fromTExp = Leaf
add :: Applicative m => m (Expr Int) -> ExprGen m (Expr Int) -> m (Expr Int)
add = liftA2 Add
expr = [|| 5 ||] `add` [|| 10 ||] This doesn't look too verbose to me. If anything now |
I'm broadly in support, at least of the untyped TH changes.
|
@Ericson2314 I'm also fine with that but I was under the impression that making
It is getting a bit frustrating. I have been trying to make So I will remove the parts about typed template haskell as I need to write a proposal anyway which completely revamps it. Hopefully by the end of the summer I will have done that. |
@goldfirere Also the point about top-level splices is that you still need to use a concrete type at the top-level splice and the maximal type of a quote is |
The "Rendered" link is outdated now, perhaps use https://github.com/mpickering/ghc-proposals/blob/overloaded-proposal/proposals/0000-overloaded-bracket.rst instead of a link to a specific commit? |
In the current proposal, I see these definitions:
Question: what instances of
|
|
Okay, then why the |
Because I think it's more consistent to always always give quotations a The |
@mpickering wait are you OK with #246 (comment) ? It precludes a newtype combining the syntax and the monad from being an instance of |
I think the quote-everywhere is more forwards-compatible too. Off topic. FWIW In some more dependent future I want to make a Reader + Writer thing based off https://cs.brown.edu/~sk/Publications/Papers/Published/pkw-inf-scope-syn-sugar/paper.pdf where you pass around references to the binding sites in a statically keyed map (as in row-types, or some equivalent). The macro evaluation does it's own name resolution, alpha-equivalent by construction, and custom binding syntax is expressible and enforceable. That's probably a huge breaking change in any event, but it seems slightly smaller one if we don't let there be any free |
@Ericson2314 I am not happy until it's possible to write instances for So no, I'm not actually in favour of it it seems. |
@mpickering OK drat, but yeah it makes more sense that you wouldn't be :). |
But this proposal looks, on the surface, that it doesn't touch top-level splices at all. So I'm unsure what to infer from this description about them.
I took the liberty to fix this myself. Thanks for your love and care to TH (and its typed variant). It is much appreciated! |
I also see that I explained this in a previous comment so perhaps you could explain with an example what you think the confusion is? Top-level splices have to instantiate
|
In general, we lack a single place where the typing rules for untyped and typed TH are laid out. (Not your fault, of course.) As we debate this proposal, another about nested quotatations, and perhaps another about overloading typed TH quotes, I acutely feel the lack of such a specification. Matthew: you are absolutely on top of all this -- could you help us along by writing the typing rules? Thanks! (Probably Latex is best for that, rather than markdown. The original paper predates the typed/untyped TH split, and so may need adjustment.) |
Yes I can write down a type system which contains both untyped and typed template haskell but probably not until after ICFP. There needs to be some additional care taken to deal with top-level splices but I have thought about how to account for this. |
Simon says:
Is that true? Then that answers my question about "instantiating In any case, I agree with Simon that your specification point (4) is in sore need of a typing rule. I can't really understand it as is. At the risk of seeming rude, I will explain how I can't understand it, trusting that you would want me to: "Refine the rules to do with splicing." This looks simply introductory. The second sentence, if I understand it now, is a no-op, saying that top-level splices don't change. "The use of nested brackets..." Now I'm lost, because the introductory sentence is about splices, but here you're talking about brackets. Maybe this sentence is to avoid readers thinking about quotes here? "A quotation that contains splices..." Now we're getting somewhere, but the sentence refers to the "constraints on the representation" and I don't know what these are. (The representation of what?) It would all be cleared up with a typing rule. |
👋 @simonpj, about accepting this . |
Thank you Matthew for revising the proposal. I declare it accepted. Let's try to get #195 revised and accepted to; it would make sense to implement both at once. Simon |
But you still want me to merge this as it is now, right? |
I believe so. Matthew has already updated it. Matthew: to double check: do you have any pending changes to this proposal? |
Yes no blockers from me. |
Code is now a newtype, so that it can be used to instantiate FreeExt. The tests still use Code for names throughout, which involves some extra boilerplate. But I think things'll become simpler again when we can use some proposals that have recently been adopted in GHC: Make Q (TExp a) into a newtype ghc-proposals/ghc-proposals#195 Overloaded Quotation Brackets ghc-proposals/ghc-proposals#246
Code is now a newtype, so that it can be used to instantiate FreeExt. The tests still use Code for names throughout, which involves some extra boilerplate. But I think things'll become simpler again when we can use some proposals that have recently been adopted in GHC: Make Q (TExp a) into a newtype ghc-proposals/ghc-proposals#195 Overloaded Quotation Brackets ghc-proposals/ghc-proposals#246
Tom Sydney Kerckhove (NorfairKing) asks: would the authors of this PR please weigh in on the discussion at commercialhaskell/path#170
The path library seems to be an example of this, and I would like to ask for some advice on how to proceed over there. |
Possibly related: https://gitlab.haskell.org/ghc/ghc/-/issues/17565 |
I posted a possible solution on that thread. By the way, as I mentioned there, it would be convenient to add a function that reinterprets a |
This caused some breakage in Short explanation: that package has a typeclass like this: class MakeBaseFunctor a where makeBaseFunctor :: a -> DecsQ
instance MakeBaseFunctor a => MakeBaseFunctor [a] where -- ...
instance MakeBaseFunctor a => MakeBaseFunctor (Q a) where -- ...
instance MakeBaseFunctor Name where -- ...
instance MakeBaseFunctor Dec where -- ... (Note that the implementations all eventually use Anyway, all of the following used to work: makeBaseFunctor ''Identity
makeBaseFunctor [''Identity, ''Maybe]
makeBaseFunctor [d| instance Recursive (Identity a) |]
makeBaseFunctor [[d| instance Recursive (Identity a) |], [d| instance Recursive (Maybe a) |]] But now the latter two fail with an ambiguous type error, since the types of the quotations are inferred to be |
Consider changing
to
|
|
That’s too bad. What we want here is some form of defaulting, so that the ambiguous type variable would be instantiated to @blamario What would it take to extend #409 in such a way that it could handle this? |
I don't see why #409 would not cover this as-is. Admittedly the motivation and the examples included in the proposal are mostly about solving the
As section 2.1 states
there's absolutely nothing preventing a declaration like
In fact it might be a good idea to recommend
in general. |
But wouldn’t this be ill-kinded? |
I retract my previous comment. I'm not sure what I did wrong, but I just tried again and it worked this time. |
Now that’s surprising, because the error message you posted makes sense! I think if you got it working, then only thanks to |
You're right, sorry I replied too quickly. I was lead from the class name to think it had the same kind as
|
Yes, |
Rendered