
Hello, The other day I was experimenting with RULES and got this warning: src/Clash/Sized/Vector.hs:2159:11: warning: [-Winline-rule-shadowing] Rule "map Pack" may never fire because rule "Class op pack" for ‘pack’ might fire first Probable fix: add phase [n] or [~n] to the competing rule | 2159 | {-# RULES "map Pack" map pack = id #-} The warning seems to suggests two things: 1. "Class op" -> "dictionary projection" are implemented as rewrite rules and executed the same way as other user-defined RULES 2. These rules run first, and you cannot run anything before them Now my question is, is 1. actually true? or is that warning just a (white) lie? If 1. is actually true, would there be any objections to adding a "-1" phase: where RULES specified to start from phase "-1" onward fire before any of the Class op rules. I'm quite willing to implement the above if A) Class op rules are actually implemented as builtin RULES; B) there a no objections to this "-1" phase. Thanks, Christiaan

Thank you for raising this issue, Christiaan! The current policy (very
early class-op inlining) is a major difficulty and the main source of
fragility in my compiling-to-categories implementation. I have a tediously
programmed and delicately balanced collection of techniques to intercept
and transform class ops to non-ops early and then transform back late for
elimination, but it doesn't work in all situations. Since class operations
roughly correspond to operations in various algebraic
abstractions---interfaces with laws---I often want to exploit exactly those
laws as rewrite rules, and yet those rules currently cannot be used
dependably. - Conal
On Fri, Mar 6, 2020 at 7:22 AM Christiaan Baaij
Hello,
The other day I was experimenting with RULES and got this warning:
src/Clash/Sized/Vector.hs:2159:11: warning: [-Winline-rule-shadowing] Rule "map Pack" may never fire because rule "Class op pack" for ‘pack’ might fire first Probable fix: add phase [n] or [~n] to the competing rule | 2159 | {-# RULES "map Pack" map pack = id #-}
The warning seems to suggests two things: 1. "Class op" -> "dictionary projection" are implemented as rewrite rules and executed the same way as other user-defined RULES 2. These rules run first, and you cannot run anything before them
Now my question is, is 1. actually true? or is that warning just a (white) lie? If 1. is actually true, would there be any objections to adding a "-1" phase: where RULES specified to start from phase "-1" onward fire before any of the Class op rules. I'm quite willing to implement the above if A) Class op rules are actually implemented as builtin RULES; B) there a no objections to this "-1" phase.
Thanks, Christiaan
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

Here’s how it works:
* The rewrite from opi (D m1 … mn) --> mi
is done by a BuiltinRule: see MkId.mkDictSelId, and the BuiltinRule that is made there.
* At the moment, BuiltinRules are always active (in all phases), see GHC.Core.ruleActivation. To allow them to be selectively active, we’d have to give them a ru_act fiels, like ordinary Rules. That would not be hard.
* The phases go
* InitialPhase
* 2
* 1
* 0
* We could make classop rules active only in phase 1 and 0, say. I don’t know what the consequences would be; running the classop to pick a method out of a dictionary in turn reveals new function applications that might want to work in phase 2, say.
* Of course you can always add more phases, but that adds compile time.
* Would you want the classop phase to be fixed for every classop? Or controllable for each classop individually. E.g. class C a where { op :: <bype> {-# INLINE [2] op #-} }
Here the intent is that, since the pragmas is in the class decl, the pragma applies to the method selector.
I remember Conal raising this before, but I’ve forgotten the resolution. I’m entirely open to changes here, if someone is willing to do the work, including checking for consequences.
Simon
From: ghc-devs

Thanks for explaining Simon!
So I personally could live with a situation where it is controllable for
each classop individually - and I'd do the work to get that in.
Where if the developer doesn't specify an INLINE pragma, it defaults to
AlwaysActive.
That way, the change only affects users who have currently annotated their
class op with an {-# INLINE[N] op #-}
(I would have to scour hackage to see if anyone has currently doing that...
I hope not...)
But now that this has been brought up: currently, does adding an {-# INLINE
op #-} (with or without phase) for a class op actually do anything?
Or is it basically superfluous because the class op already gets a
BuiltInRule that's equal to INLINE AlwaysActive?
Or does it affect whether a default implementation for the method gets
inlined into the dictionary?
If the latter, I guess we should use SPECIALIZE instead of INLINE for
controlling the rule phase of the class op... unless that SPECIALIZE also
has an effect on the class op default implementation...
Thanks,
Christiaan
On Sat, 7 Mar 2020 at 00:02, Simon Peyton Jones
Here’s how it works:
- The rewrite from opi (D m1 … mn) à mi
is done by a BuiltinRule: see MkId.mkDictSelId, and the BuiltinRule that is made there.
- At the moment, BuiltinRules are always active (in all phases), see GHC.Core.ruleActivation. To allow them to be selectively active, we’d have to give them a ru_act fiels, like ordinary Rules. That would not be hard.
- The phases go - InitialPhase - 2 - 1 - 0
- We could make classop rules active only in phase 1 and 0, say. I don’t know what the consequences would be; running the classop to pick a method out of a dictionary in turn reveals new function applications that might want to work in phase 2, say.
- Of course you can always add more phases, but that adds compile time.
- Would you want the classop phase to be fixed for every classop? Or controllable for each classop individually. E.g. class C a where { op :: <bype> {-# INLINE [2] op #-} }
Here the intent is that, since the pragmas is in the class decl, the pragma applies to the method selector.
I remember Conal raising this before, but I’ve forgotten the resolution. I’m entirely open to changes here, if someone is willing to do the work, including checking for consequences.
Simon
*From:* ghc-devs
*On Behalf Of *Conal Elliott *Sent:* 06 March 2020 17:37 *To:* Christiaan Baaij *Cc:* ghc-devs *Subject:* Re: Class op rules Thank you for raising this issue, Christiaan! The current policy (very early class-op inlining) is a major difficulty and the main source of fragility in my compiling-to-categories implementation. I have a tediously programmed and delicately balanced collection of techniques to intercept and transform class ops to non-ops early and then transform back late for elimination, but it doesn't work in all situations. Since class operations roughly correspond to operations in various algebraic abstractions---interfaces with laws---I often want to exploit exactly those laws as rewrite rules, and yet those rules currently cannot be used dependably. - Conal
On Fri, Mar 6, 2020 at 7:22 AM Christiaan Baaij < christiaan.baaij@gmail.com> wrote:
Hello,
The other day I was experimenting with RULES and got this warning:
src/Clash/Sized/Vector.hs:2159:11: warning: [-Winline-rule-shadowing] Rule "map Pack" may never fire because rule "Class op pack" for ‘pack’ might fire first Probable fix: add phase [n] or [~n] to the competing rule | 2159 | {-# RULES "map Pack" map pack = id #-}
The warning seems to suggests two things:
1. "Class op" -> "dictionary projection" are implemented as rewrite rules and executed the same way as other user-defined RULES
2. These rules run first, and you cannot run anything before them
Now my question is, is 1. actually true? or is that warning just a (white) lie?
If 1. is actually true, would there be any objections to adding a "-1" phase: where RULES specified to start from phase "-1" onward fire before any of the Class op rules.
I'm quite willing to implement the above if A) Class op rules are actually implemented as builtin RULES; B) there a no objections to this "-1" phase.
Thanks,
Christiaan
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

But now that this has been brought up: currently, does adding an {-# INLINE op #-} (with or without phase) for a class op actually do anything?
Currently it does nothing, I think, and therefore should perhaps be rejected today. So I hope no one is doing that. Worth double checking:
* Hackage, to check that no one has INLINE on a method in a class decl
* GHC, to check that an INLINE on method in a class decl is ignored.
In contrast, an INLINE on an instance decl should mean that that particular class op instance method is inlined. I hope this works correctly today.
So I personally could live with a situation where it is controllable for each classop individually - and I'd do the work to get that in.
OK. This is actually user facing, so I think the right thing is to write a short GHC Proposal. It needn’t take long to get approved. But it does get more eyes on it. And it provides a solid write up to refer to from the implementation.
You could draw on this thread for the raw material, so it would not be hard to write.
Simon
From: Christiaan Baaij

so i did some poking around see eg
https://gitlab.haskell.org/ghc/ghc/blob/4898df1cc25132dc9e2599d4fa4e1bbc9423...
, and at the moment, the simplifier phase number ordering internally (in
order from first to last)
"Initial phase" --- essentially positive infinity
.... -- currently we can add new phases here
2
1
0
-------
This actually surprised me, as i've always (at least from how rules are
usually written in eg vector) thought it was counting UP!
@Christiaan ... so we'd need a Pre initial phase count? that happens
before Initial phase?
On Fri, Mar 6, 2020 at 10:22 AM Christiaan Baaij
Hello,
The other day I was experimenting with RULES and got this warning:
src/Clash/Sized/Vector.hs:2159:11: warning: [-Winline-rule-shadowing] Rule "map Pack" may never fire because rule "Class op pack" for ‘pack’ might fire first Probable fix: add phase [n] or [~n] to the competing rule | 2159 | {-# RULES "map Pack" map pack = id #-}
The warning seems to suggests two things: 1. "Class op" -> "dictionary projection" are implemented as rewrite rules and executed the same way as other user-defined RULES 2. These rules run first, and you cannot run anything before them
Now my question is, is 1. actually true? or is that warning just a (white) lie? If 1. is actually true, would there be any objections to adding a "-1" phase: where RULES specified to start from phase "-1" onward fire before any of the Class op rules. I'm quite willing to implement the above if A) Class op rules are actually implemented as builtin RULES; B) there a no objections to this "-1" phase.
Thanks, Christiaan
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

As a workaround, can you try this?
https://stackoverflow.com/a/32133083/477476
On Fri, Mar 6, 2020, 23:23 Christiaan Baaij
Hello,
The other day I was experimenting with RULES and got this warning:
src/Clash/Sized/Vector.hs:2159:11: warning: [-Winline-rule-shadowing] Rule "map Pack" may never fire because rule "Class op pack" for ‘pack’ might fire first Probable fix: add phase [n] or [~n] to the competing rule | 2159 | {-# RULES "map Pack" map pack = id #-}
The warning seems to suggests two things: 1. "Class op" -> "dictionary projection" are implemented as rewrite rules and executed the same way as other user-defined RULES 2. These rules run first, and you cannot run anything before them
Now my question is, is 1. actually true? or is that warning just a (white) lie? If 1. is actually true, would there be any objections to adding a "-1" phase: where RULES specified to start from phase "-1" onward fire before any of the Class op rules. I'm quite willing to implement the above if A) Class op rules are actually implemented as builtin RULES; B) there a no objections to this "-1" phase.
Thanks, Christiaan
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

That workaround is fragile for me:
When I put everything into one file, the "fromList/toList" rule fires.
However, when I put the test1 and main definitions into a separate file,
the "fromList/toList" rule no longer fires.
The reason for that seems to be that " fromList' = fromList " is rewritten
to " fromList' = fromList' ", and then the strictness/demand analysis flags
it up as always bottoming.
Then in the file where we write `test1 x = fromList (toList x)`, it gets
rewritten to `test1 x = fromList' (toList x)`, after which (because of the
always bottoming) it gets rewritten to `test1 _ = case fromList' of {}`
On Sat, 7 Mar 2020 at 02:56, Dr. ÉRDI Gergő
As a workaround, can you try this? https://stackoverflow.com/a/32133083/477476
On Fri, Mar 6, 2020, 23:23 Christiaan Baaij
wrote: Hello,
The other day I was experimenting with RULES and got this warning:
src/Clash/Sized/Vector.hs:2159:11: warning: [-Winline-rule-shadowing] Rule "map Pack" may never fire because rule "Class op pack" for ‘pack’ might fire first Probable fix: add phase [n] or [~n] to the competing rule | 2159 | {-# RULES "map Pack" map pack = id #-}
The warning seems to suggests two things: 1. "Class op" -> "dictionary projection" are implemented as rewrite rules and executed the same way as other user-defined RULES 2. These rules run first, and you cannot run anything before them
Now my question is, is 1. actually true? or is that warning just a (white) lie? If 1. is actually true, would there be any objections to adding a "-1" phase: where RULES specified to start from phase "-1" onward fire before any of the Class op rules. I'm quite willing to implement the above if A) Class op rules are actually implemented as builtin RULES; B) there a no objections to this "-1" phase.
Thanks, Christiaan
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
participants (5)
-
Carter Schonwald
-
Christiaan Baaij
-
Conal Elliott
-
Dr. ÉRDI Gergő
-
Simon Peyton Jones