Re: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Clinton Mead
Ben,

The suggestion of erroring if the inline pragma was not there was just
because I thought it would be better than silently doing something
different. But that's just a subjective opinion, it's not core to what I'm
proposing.

Indeed there are two other options:

1. Make levity polymorphic functions implicitly inline OR
2. Compile a version which wraps all the levity polymorphism in boxes.

Either approach would mean the program would still be accepted with or
without the pragma. Whether either of them are a good idea is debatable,
but it shows it's not necessary to require a pragma.

So if it's important that excluding a pragma doesn't result in a program
being rejected, either of the above options would solve that issue.

On Sat, Oct 9, 2021 at 2:06 AM Ben Gamari  wrote:

> Chris Smith  writes:
>
> > On Fri, Oct 8, 2021 at 10:51 AM Ben Gamari  wrote:
> >
> >> In my mind the fundamental problem with this approach is that it means
> >> that a program's acceptance by the compiler hinges upon pragmas.
> >> This is a rather significant departure from the status quo, where one
> >> can remove all pragmas and still end up with a well-formed program.
> >> In this sense, pragmas aren't really part of the Haskell language but
> >> are rather bits of interesting metadata that the compiler may or may not
> >> pay heed to.
> >>
> >
> > I don't believe this is really the status quo.  In particular, the
> pragmas
> > relating to overlapping instances definitely do affect whether a program
> > type-checks or not.
>
> Yes, this is a fair point. Moreover, the same can be said of
> LANGUAGE pragmas more generally. I will rephrase my statement to reflect
> what was in my head when I initially wrote it:
>
> >> In my mind the fundamental problem with this approach is that it means
> >> that a program's acceptance by the compiler hinges upon INLINE pragmas.
> >> This is a rather significant departure from the status quo, where one
> >> can remove all INLINE, INLINEABLE, RULES, and SPECIALISE pragmas and
> >> still end up with a well-formed program.
>
> These pragmas all share the property that they don't change program
> semantics but rather merely affect operational behavior. Consequently,
> they should not change whether a program should be accepted.
>
> Cheers,
>
> - Ben
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Krzysztof Gogolewski
Note that you can use Typed Template Haskell as a workaround, e.g.

f :: forall r (a :: TYPE r). Code Q (a -> a)
f = [||\x -> x||]

In the future this might be integrated better with the restriction
polymorphism checking:

https://gitlab.haskell.org/ghc/ghc/-/issues/18170
https://gitlab.haskell.org/ghc/ghc/-/wikis/FixedRuntimeRep#typed-template-haskell

On Fri, Oct 8, 2021 at 5:19 PM Simon Peyton Jones via ghc-devs
 wrote:
>
> We do have a few such functions, and we give them a “compulsory unfolding” 
> which means they MUST be inlined at EVERY call site.  But
>
>
>
> Usually if a module exports a function, it generates code for that function. 
> But for these guys it can’t.   We don’t have a mechanism for *not* generating 
> code for user-defined functions.  We could add an INLINE-COMPULSORY pragma 
> perhaps.
> Even then we’d have to check that every call of such a function is applied to 
> enough arguments to get rid of all levity/representation polymorphism; so 
> that when it is inlined all is good. It’s not clear how to do that in general.
>
>
>
> That’s the kind of thing Richard means by “templates”.
>
>
>
> Simon
>
>
>
> PS: I am leaving Microsoft at the end of November 2021, at which point 
> simo...@microsoft.com will cease to work.  Use simon.peytonjo...@gmail.com 
> instead.  (For now, it just forwards to simo...@microsoft.com.)
>
>
>
> From: ghc-devs  On Behalf Of Clinton Mead
> Sent: 08 October 2021 00:37
> To: ghc-devs@haskell.org
> Subject: Why can't arguments be levity polymorphic for inline functions?
>
>
>
> Hi All
>
>
>
> Not sure if this belongs in ghc-users or ghc-devs, but it seemed devy enough 
> to put it here.
>
>
>
> Section 6.4.12.1 of the GHC user manual points out, if we allowed levity 
> polymorphic arguments, then we would have no way to compile these functions, 
> because the code required for different levites is different.
>
>
>
> However, if such a function is {-# INLINE #-} or {-# INLINABLE #-} there's no 
> need to compile it as it's full definition is in the interface file. Callers 
> can just compile it themselves with the levity they require. Indeed callers 
> of inline functions already compile their own versions even without levity 
> polymorphism (for example, presumably inlining function calls that are known 
> at compile time).
>
>
>
> The only sticking point to this that I could find was that GHC will only 
> inline the function if it is fully applied, which suggests that the 
> possibility of partial application means we can't inline and hence need a 
> compiled version of the code. But this seems like a silly restriction, as we 
> have the full RHS of the definition in the interface file. The caller can 
> easily create and compile it's own partially applied version. It should be 
> able to do this regardless of levity.
>
>
>
> It seems to me we're okay as long as the following three things aren't true 
> simultaneously:
>
>
>
> 1. Blah has levity polymorphic arguments
>
> 2. Blah is exported
>
> 3. Blah is not inline
>
>
>
> If a function "Blah" is not exported, we shouldn't care about levity 
> polymorphic arguments, because we have it's RHS on hand in the current module 
> and compile it as appropriate. And if it's inline, we're exposing it's full 
> RHS to other callers so we're still fine also. Only when these three 
> conditions combine should we give an error, say like:
>
>
>
> "Blah has levity polymorphic arguments, is exported, and is not inline. 
> Please either remove levity polymorphic arguments, not export it or add an  
> {-# INLINE #-} or {-# INLINABLE #-} pragma.
>
>
>
> I presume however there are some added complications that I don't understand, 
> and I'm very interested in what they are as I presume they'll be quite 
> interesting.
>
>
>
> Thanks,
> Clinton
>
>
>
> ___
> ghc-devs mailing list
> ghc-devs@haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


RE: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Simon Peyton Jones via ghc-devs
We do have a few such functions, and we give them a "compulsory unfolding" 
which means they MUST be inlined at EVERY call site.  But


  *   Usually if a module exports a function, it generates code for that 
function. But for these guys it can't.   We don't have a mechanism for *not* 
generating code for user-defined functions.  We could add an INLINE-COMPULSORY 
pragma perhaps.
  *   Even then we'd have to check that every call of such a function is 
applied to enough arguments to get rid of all levity/representation 
polymorphism; so that when it is inlined all is good. It's not clear how to do 
that in general.

That's the kind of thing Richard means by "templates".

Simon

PS: I am leaving Microsoft at the end of November 2021, at which point 
simo...@microsoft.com will cease to work.  Use 
simon.peytonjo...@gmail.com instead.  (For 
now, it just forwards to simo...@microsoft.com.)

From: ghc-devs  On Behalf Of Clinton Mead
Sent: 08 October 2021 00:37
To: ghc-devs@haskell.org
Subject: Why can't arguments be levity polymorphic for inline functions?

Hi All

Not sure if this belongs in ghc-users or ghc-devs, but it seemed devy enough to 
put it here.

Section 
6.4.12.1
 of the GHC user manual points out, if we allowed levity polymorphic arguments, 
then we would have no way to compile these functions, because the code required 
for different levites is different.

However, if such a function is {-# INLINE #-} or {-# INLINABLE #-} there's no 
need to compile it as it's full definition is in the interface file. Callers 
can just compile it themselves with the levity they require. Indeed callers of 
inline functions already compile their own versions even without levity 
polymorphism (for example, presumably inlining function calls that are known at 
compile time).

The only sticking point to this that I could find was that GHC will only inline 
the function if it is fully 
applied,
 which suggests that the possibility of partial application means we can't 
inline and hence need a compiled version of the code. But this seems like a 
silly restriction, as we have the full RHS of the definition in the interface 
file. The caller can easily create and compile it's own partially applied 
version. It should be able to do this regardless of levity.

It seems to me we're okay as long as the following three things aren't true 
simultaneously:

1. Blah has levity polymorphic arguments
2. Blah is exported
3. Blah is not inline

If a function "Blah" is not exported, we shouldn't care about levity 
polymorphic arguments, because we have it's RHS on hand in the current module 
and compile it as appropriate. And if it's inline, we're exposing it's full RHS 
to other callers so we're still fine also. Only when these three conditions 
combine should we give an error, say like:

"Blah has levity polymorphic arguments, is exported, and is not inline. Please 
either remove levity polymorphic arguments, not export it or add an  {-# INLINE 
#-} or {-# INLINABLE #-} pragma.

I presume however there are some added complications that I don't understand, 
and I'm very interested in what they are as I presume they'll be quite 
interesting.

Thanks,
Clinton

___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Ben Gamari
Chris Smith  writes:

> On Fri, Oct 8, 2021 at 10:51 AM Ben Gamari  wrote:
>
>> In my mind the fundamental problem with this approach is that it means
>> that a program's acceptance by the compiler hinges upon pragmas.
>> This is a rather significant departure from the status quo, where one
>> can remove all pragmas and still end up with a well-formed program.
>> In this sense, pragmas aren't really part of the Haskell language but
>> are rather bits of interesting metadata that the compiler may or may not
>> pay heed to.
>>
>
> I don't believe this is really the status quo.  In particular, the pragmas
> relating to overlapping instances definitely do affect whether a program
> type-checks or not.

Yes, this is a fair point. Moreover, the same can be said of
LANGUAGE pragmas more generally. I will rephrase my statement to reflect
what was in my head when I initially wrote it:

>> In my mind the fundamental problem with this approach is that it means
>> that a program's acceptance by the compiler hinges upon INLINE pragmas.
>> This is a rather significant departure from the status quo, where one
>> can remove all INLINE, INLINEABLE, RULES, and SPECIALISE pragmas and
>> still end up with a well-formed program.

These pragmas all share the property that they don't change program
semantics but rather merely affect operational behavior. Consequently,
they should not change whether a program should be accepted.

Cheers,

- Ben


signature.asc
Description: PGP signature
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Richard Eisenberg


> On Oct 8, 2021, at 10:51 AM, Ben Gamari  wrote:
> In my mind the fundamental problem with this approach is that it means
> that a program's acceptance by the compiler hinges upon pragmas.

I think being able to ignore pragmas is a worthy goal, but one we're rather far 
short of, at the moment: overlapping pragmas (as Chris has pointed out), 
language pragmas (!), options pragmas setting -Werror, plugin pragmas, maybe 
others.

Richard
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Chris Smith
On Fri, Oct 8, 2021 at 10:51 AM Ben Gamari  wrote:

> In my mind the fundamental problem with this approach is that it means
> that a program's acceptance by the compiler hinges upon pragmas.
> This is a rather significant departure from the status quo, where one
> can remove all pragmas and still end up with a well-formed program.
> In this sense, pragmas aren't really part of the Haskell language but
> are rather bits of interesting metadata that the compiler may or may not
> pay heed to.
>

I don't believe this is really the status quo.  In particular, the pragmas
relating to overlapping instances definitely do affect whether a program
type-checks or not.
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Ben Gamari
Clinton Mead  writes:

> Hi All
>
> Not sure if this belongs in ghc-users or ghc-devs, but it seemed devy
> enough to put it here.
>
> Section 6.4.12.1
> 
> of the GHC user manual points out, if we allowed levity polymorphic
> arguments, then we would have no way to compile these functions, because
> the code required for different levites is different.
>
> However, if such a function is {-# INLINE #-} or {-# INLINABLE #-} there's
> no need to compile it as it's full definition is in the interface file.
> Callers can just compile it themselves with the levity they require. Indeed
> callers of inline functions already compile their own versions even without
> levity polymorphism (for example, presumably inlining function calls that
> are known at compile time).
>
> The only sticking point to this that I could find was that GHC will only
> inline the function if it is fully applied
> ,
> which suggests that the possibility of partial application means we can't
> inline and hence need a compiled version of the code. But this seems like a
> silly restriction, as we have the full RHS of the definition in the
> interface file. The caller can easily create and compile it's own partially
> applied version. It should be able to do this regardless of levity.
>
> It seems to me we're okay as long as the following three things aren't true
> simultaneously:
>
> 1. Blah has levity polymorphic arguments
> 2. Blah is exported
> 3. Blah is not inline
>
In my mind the fundamental problem with this approach is that it means
that a program's acceptance by the compiler hinges upon pragmas.
This is a rather significant departure from the status quo, where one
can remove all pragmas and still end up with a well-formed program. 
In this sense, pragmas aren't really part of the Haskell language but
are rather bits of interesting metadata that the compiler may or may not
pay heed to.

Given that levity polymorphic functions have rather deep implications on
compilation strategy, I suspect that the cleanest path to allowing it
would be to further extend the type system (for instance, with a new
"macro expanding" arrow notion).

Cheers,

- Ben


signature.asc
Description: PGP signature
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Richard Eisenberg
One significant problem is that {-# INLINE #-} functions are not actually 
always inlined! Specifically, if an inline-function is not passed all of its 
arguments, it will not be inlined. This poses a problem for levity-polymorphic 
functions, and GHC already does some special handling of the few 
levity-polymorphic primitives, in case they are ever used without all of their 
arguments.

As for boxing levity-polymorphic arguments: that's plausible, but then I think 
you've defeated the programmer's intended aim.

The solution to me is some kind of so-called template polymorphism 
. This might 
work, but it would take a fair amount of design work first.

Richard

> On Oct 7, 2021, at 7:36 PM, Clinton Mead  wrote:
> 
> Hi All
> 
> Not sure if this belongs in ghc-users or ghc-devs, but it seemed devy enough 
> to put it here. 
> 
> Section 6.4.12.1 
> 
>  of the GHC user manual points out, if we allowed levity polymorphic 
> arguments, then we would have no way to compile these functions, because the 
> code required for different levites is different. 
> 
> However, if such a function is {-# INLINE #-} or {-# INLINABLE #-} there's no 
> need to compile it as it's full definition is in the interface file. Callers 
> can just compile it themselves with the levity they require. Indeed callers 
> of inline functions already compile their own versions even without levity 
> polymorphism (for example, presumably inlining function calls that are known 
> at compile time).
> 
> The only sticking point to this that I could find was that GHC will only 
> inline the function if it is fully applied 
> ,
>  which suggests that the possibility of partial application means we can't 
> inline and hence need a compiled version of the code. But this seems like a 
> silly restriction, as we have the full RHS of the definition in the interface 
> file. The caller can easily create and compile it's own partially applied 
> version. It should be able to do this regardless of levity. 
> 
> It seems to me we're okay as long as the following three things aren't true 
> simultaneously:
> 
> 1. Blah has levity polymorphic arguments
> 2. Blah is exported
> 3. Blah is not inline
> 
> If a function "Blah" is not exported, we shouldn't care about levity 
> polymorphic arguments, because we have it's RHS on hand in the current module 
> and compile it as appropriate. And if it's inline, we're exposing it's full 
> RHS to other callers so we're still fine also. Only when these three 
> conditions combine should we give an error, say like:
> 
> "Blah has levity polymorphic arguments, is exported, and is not inline. 
> Please either remove levity polymorphic arguments, not export it or add an  
> {-# INLINE #-} or {-# INLINABLE #-} pragma.
> 
> I presume however there are some added complications that I don't understand, 
> and I'm very interested in what they are as I presume they'll be quite 
> interesting. 
> 
> Thanks,
> Clinton
> 
> ___
> ghc-devs mailing list
> ghc-devs@haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Clinton Mead
Thanks for your reply Andreas.

Just some further thoughts, perhaps we don't even require inline.

Correct me if I'm wrong, but couldn't we compile even functions with levity
polymorphic arguments by just boxing all the arguments?

This would also mean the caller would have to box arguments before passing.

You'd also need to box any working variables inside the function with
levity other than `Type`.

This to a certain extent defeats the purpose of levity polymorphism when
it's intended as an optimisation to avoid boxed types, but it does give a
fallback we can always use.

Yes, if you inline you can get code bloat. But that's a risk when you
inline any function.

Cheers,
Clinton

On Fri, Oct 8, 2021 at 11:39 PM Andreas Klebinger 
wrote:

> Hey Clinton,
>
> I think the state of things is best summarised it's in principle possible
> to implement. But it's unclear how best to do so
> or even if it's worth having this feature at all.
>
> The biggest issue being code bloat.
>
> As you say a caller could create it's own version of the function with the
> right kind of argument type.
> But that means duplicating the function for every use site (although some
> might be able to be commoned up). Potentially causing a lot of code
> bloat and compile time overhead.
>
> In a similar fashion we could create each potential version we need from
> the get go to avoid duplicating the same function.
> But that runs the risk of generating far more code than what is actually
> used.
>
> Last but not least GHC currently doesn't always load unfoldings. In
> particular if you compile a module with optimizations disabled the RHS is
> currently *not*
> available to the compiler when looking at the use site. There already is a
> mechanism to bypass this in GHC where a function *must* be inlined
> (compulsory unfoldings).
> But it's currently reserved for built in functions. We could just make
> INLINE bindings compulsory if they have levity-polymorphic arguments sure.
> But again it's not clear
> this is really desireable.
>
> I don't think this has to mean we couldn't change how things work to
> accomodate levity-polymorphic arguments. It just seems it's unclear what a
> good design
> would look like and if it's worth having.
>
> Cheers
> Andreas
> Am 08/10/2021 um 01:36 schrieb Clinton Mead:
>
> Hi All
>
> Not sure if this belongs in ghc-users or ghc-devs, but it seemed devy
> enough to put it here.
>
> Section 6.4.12.1
> 
> of the GHC user manual points out, if we allowed levity polymorphic
> arguments, then we would have no way to compile these functions, because
> the code required for different levites is different.
>
> However, if such a function is {-# INLINE #-} or {-# INLINABLE #-}
> there's no need to compile it as it's full definition is in the interface
> file. Callers can just compile it themselves with the levity they require.
> Indeed callers of inline functions already compile their own versions even
> without levity polymorphism (for example, presumably inlining function
> calls that are known at compile time).
>
> The only sticking point to this that I could find was that GHC will only
> inline the function if it is fully applied
> ,
> which suggests that the possibility of partial application means we can't
> inline and hence need a compiled version of the code. But this seems like a
> silly restriction, as we have the full RHS of the definition in the
> interface file. The caller can easily create and compile it's own partially
> applied version. It should be able to do this regardless of levity.
>
> It seems to me we're okay as long as the following three things aren't
> true simultaneously:
>
> 1. Blah has levity polymorphic arguments
> 2. Blah is exported
> 3. Blah is not inline
>
> If a function "Blah" is not exported, we shouldn't care about levity
> polymorphic arguments, because we have it's RHS on hand in the current
> module and compile it as appropriate. And if it's inline, we're exposing
> it's full RHS to other callers so we're still fine also. Only when these
> three conditions combine should we give an error, say like:
>
> "Blah has levity polymorphic arguments, is exported, and is not inline.
> Please either remove levity polymorphic arguments, not export it or add an  
> {-#
> INLINE #-} or {-# INLINABLE #-} pragma.
>
> I presume however there are some added complications that I don't
> understand, and I'm very interested in what they are as I presume they'll
> be quite interesting.
>
> Thanks,
> Clinton
>
>
> ___
> ghc-devs mailing 
> listghc-devs@haskell.orghttp://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-dev

Re: Why can't arguments be levity polymorphic for inline functions?

2021-10-08 Thread Andreas Klebinger

Hey Clinton,

I think the state of things is best summarised it's in principle
possible to implement. But it's unclear how best to do so
or even if it's worth having this feature at all.

The biggest issue being code bloat.

As you say a caller could create it's own version of the function with
the right kind of argument type.
But that means duplicating the function for every use site (although
some might be able to be commoned up). Potentially causing a lot of code
bloat and compile time overhead.

In a similar fashion we could create each potential version we need from
the get go to avoid duplicating the same function.
But that runs the risk of generating far more code than what is actually
used.

Last but not least GHC currently doesn't always load unfoldings. In
particular if you compile a module with optimizations disabled the RHS
is currently *not*
available to the compiler when looking at the use site. There already is
a mechanism to bypass this in GHC where a function *must* be inlined
(compulsory unfoldings).
But it's currently reserved for built in functions. We could just make
INLINE bindings compulsory if they have levity-polymorphic arguments
sure. But again it's not clear
this is really desireable.

I don't think this has to mean we couldn't change how things work to
accomodate levity-polymorphic arguments. It just seems it's unclear what
a good design
would look like and if it's worth having.

Cheers
Andreas

Am 08/10/2021 um 01:36 schrieb Clinton Mead:

Hi All

Not sure if this belongs in ghc-users or ghc-devs, but it seemed devy
enough to put it here.

Section 6.4.12.1

of the GHC user manual points out, if we allowed levity polymorphic
arguments, then we would have no way to compile these functions,
because the code required for different levites is different.

However, if such a function is {-# INLINE #-} or{-# INLINABLE #-}
there's no need to compile it as it's full definition is in the
interface file. Callers can just compile it themselves with the levity
they require. Indeed callers of inline functions already compile their
own versions even without levity polymorphism (for example, presumably
inlining function calls that are known at compile time).

The only sticking point to this that I could find was that GHC will
only inline the function if it is fully applied
,
which suggests that the possibility of partial application means we
can't inline and hence need a compiled version of the code. But this
seems like a silly restriction, as we have the full RHS of the
definition in the interface file. The caller can easily create and
compile it's own partially applied version. It should be able to do
this regardless of levity.

It seems to me we're okay as long as the following three things aren't
true simultaneously:

1. Blah has levity polymorphic arguments
2. Blah is exported
3. Blah is not inline

If a function "Blah" is not exported, we shouldn't care about levity
polymorphic arguments, because we have it's RHS on hand in the current
module and compile it as appropriate. And if it's inline, we're
exposing it's full RHS to other callers so we're still fine also. Only
when these three conditions combine should we give an error, say like:

"Blah has levity polymorphic arguments, is exported, and is not
inline. Please either remove levity polymorphic arguments, not export
it or add an {-# INLINE #-} or {-# INLINABLE #-} pragma.

I presume however there are some added complications that I don't
understand, and I'm very interested in what they are as I presume
they'll be quite interesting.

Thanks,
Clinton


___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs