-
Notifications
You must be signed in to change notification settings - Fork 58
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
traverse Array with Maybe more quickly #142
base: master
Are you sure you want to change the base?
Conversation
I like this. For Side note: it's most unfortunate for |
I've just added Aside from that, are there other issues you see with this? Other types worth supporting? |
I don't understand why you think the manual copies (with rewrite rules to match) wouldn't help. |
I think GHC will produce the same core. |
Quite possibly, but you won't be depending on having ExceptT in
transformers.
…On Apr 22, 2018 10:58 AM, "Andrew Martin" ***@***.***> wrote:
I think GHC will produce the same core.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_VIxxCgLXNeO_AbANLNZKCV4NYIzks5trJqYgaJpZM4Tdr0z>
.
|
Ah, it was consistent behavior with all versions of containers that was your concern. I've changed it as you suggested. Also, I added a benchmark just to see if there was a performance difference between the two implementations. They have identical performance (Wooh GHC!). |
All these rewrite rules (including the ones I wrote) feel somewhat unsatisfactory, because they completely fall down for transformers. I'm wondering if there might be a way to catch known transformations of known base monads, using rewrite rules with fall-backs. Roughly speaking, rewrite applications of known transformers recursively until we reach a known base monad (in which case we can rewrite to something particularly efficient) or fail to do so, in which case we ultimately inline to the usual case. By the way: what sorts of benchmark speed-ups were you able to demonstrate from the |
…of Array to stock applicative traversal
I've just added a benchmark to compare the two:
This is on a pretty noisy box, but there's about a 5x speedup. On
About a 200x speedup on my noisy box. This is because, for I like your idea about recursively rewriting. I'm going to give this a try. |
I can't find a way to make this work. Consider what a rewrite rule for
Here's the problem: in the rewrite rule, we have no way to tell GHC that |
In fact, in the rewrite rule, GHC doesn't even know that |
You certainly can't do it that way. I'm not sure if you can do it at all or
not, but if so it will require rewrite rules "all the way down" to a base
type a rule matches on.
…On Mon, Apr 23, 2018, 3:36 PM Andrew Martin ***@***.***> wrote:
All these rewrite rules (including the ones I wrote) feel somewhat
unsatisfactory, because they completely fall down for transformers. I'm
wondering if there might be a way to catch known transformations of known
base monads, using rewrite rules with fall-backs.
I can't find a way to make this work. Consider what a rewrite rule for
MaybeT might look like:
"traverse/MaybeT" forall (f :: a -> MaybeT m b). traverseArray f = ...
Here's the problem: in the rewrite rule, we have no way to tell GHC that m
needs to have a PrimMonad constraint. GHC appears to have a syntax that
tricks the user into thinking they can do this, but it doesn't actually
work.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_dZCqTaNqZmbf1VIp02zVy3_B4Aaks5tri04gaJpZM4Tdr0z>
.
|
The basic idea would be to step through the layers of monad transformers
you recognize, recording how each one transforms a monad. Then at the
bottom, find a base monad you recognize and build up the ultimate bind and
return. I'm not sure this can be done, but I strongly suspect it can.
…On Mon, Apr 23, 2018, 3:43 PM Andrew Martin ***@***.***> wrote:
In fact, in the rewrite rule, GHC doesn't even know that m has an
Applicative instance.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_bT_4FDHXBWsf7sCOMq0KZFsl94lks5tri7igaJpZM4Tdr0z>
.
|
I'm still not able to follow how this is supposed to look. Going back to
I cannot see anything that could go on the RHS (other than |
Wait, I think I might be beginning to see a way. |
Wait, I think I might be beginning to see a way.
Me too 😉
… —
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_UxLd-9G6tLrM5RAYiQkfb2cd6_xks5trjSQgaJpZM4Tdr0z>
.
|
The race is on. |
I think we can get MaybeT, ExceptT, and StateT, but not WriterT, RWST, or
ErrorT (since those have side constraints). I haven't actually tested my
rules, though, so I don't know if they fire or, if they do, whether they
produce decent code.
…On Mon, Apr 23, 2018, 4:12 PM David Feuer ***@***.***> wrote:
Wait, I think I might be beginning to see a way.
>
Me too 😉
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <#142 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ABzi_UxLd-9G6tLrM5RAYiQkfb2cd6_xks5trjSQgaJpZM4Tdr0z>
> .
>
|
Have you pushed these somewhere? |
No. Thus far they're pretty much faked up. When I'm home I'll (try to) make
them a bit less fake and push to show you.
…On Mon, Apr 23, 2018, 4:53 PM Andrew Martin ***@***.***> wrote:
Have you pushed these somewhere?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_aDZfEmPXOF-IzFWAsJpLuOxWDjDks5trj9TgaJpZM4Tdr0z>
.
|
Until then, I strongly urge you to give it a good try. You may well come up
with a better idea than I did, and in any case you'll certainly learn some
things.
…On Mon, Apr 23, 2018, 5:05 PM David Feuer ***@***.***> wrote:
No. Thus far they're pretty much faked up. When I'm home I'll (try to)
make them a bit less fake and push to show you.
On Mon, Apr 23, 2018, 4:53 PM Andrew Martin ***@***.***>
wrote:
> Have you pushed these somewhere?
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <#142 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ABzi_aDZfEmPXOF-IzFWAsJpLuOxWDjDks5trj9TgaJpZM4Tdr0z>
> .
>
|
Hrmm... I'm able to write code that at least type checks to handle (some) transformers on top of |
It feels like we’re bordering on feature / ideas for improving rules based
optimization. What is it we wish we could say / can only express via hand
scripted hermit tool optimization’s?
David: have you tried out hermit?
…On Mon, Apr 23, 2018 at 9:21 PM David Feuer ***@***.***> wrote:
Hrmm... I'm able to write code that at least type checks to handle (some)
transformers on top of ST and IO, but I'm actually not sure how to handle
transformers on top of Maybe, Either, Identity, etc. Do you think it's
doable? If not for the annoying limits on instance discovery, do you think
you could write rules? Maybe those could inspire. Anyway, I'll upload what
I have within the hour.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAAQwoT8qU8bQdwXqJnxjl4erPb-ylDkks5trn4jgaJpZM4Tdr0z>
.
|
@cartazio, I've only looked at hermit briefly. It's rather complicated. The basic limitation is basically that the instance resolution derivations drop away after type checking. So for example the simplifier doesn't know how GHC resolved |
Is there ways this could be changed in ghc?
Seems like it would be at least a useful discussion as feature request
motivated by what optimization’s you want to be able to say simply.
I’d like it if we can keep primitive simple if we can. At some point too
much rules optImitation can hinder easy of changing internals. Though we
don’t have much internals going on :)
…On Mon, Apr 23, 2018 at 11:50 PM David Feuer ***@***.***> wrote:
@cartazio <https://github.com/cartazio>, I've only looked at hermit
briefly. It's rather complicated. The basic limitation is basically that
the instance resolution derivations drop away after type checking. So for
example the simplifier doesn't know how GHC resolved PrimMonad (WriterT w
m) and therefore doesn't know Monad m or Monoid w.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAAQwp1B8vcjC9gp9iAxWzcxqVfS4i63ks5trqD8gaJpZM4Tdr0z>
.
|
For stacks based on |
Separately, I'm considering a simpler general version that might work somewhat better than the one I put in before. In particular, we can go back to something somewhat list-like, but using a list that holds multiple elements per cons. I need to do some benchmarking. |
Undoubtedly, yours is much simpler. In my most recent commit, I was mostly playing around just to see what it takes to make things like Maybe and Either accepted as the base monad. It’s helped me understand the problem better. I have another idea for how to extend your solution to accept different base monads that I am going to try soon. |
Question: why do we need the rewrite rules? a) is it because we can better specialize the code ? b) is it because you want to be "Afine/ linear resource safe"? |
We want rewrite rules for speed. They're not supposed to change semantics
any.
…On Fri, Apr 27, 2018, 12:33 PM Carter Tazio Schonwald < ***@***.***> wrote:
Question: why do we need the rewrite rules?
a) is it because we can better specialize the code ?
b) is it because you want to be "Afine/ linear resource safe"?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_RDKD9u2DR7vKBuuEX15qtO00cceks5ts0hUgaJpZM4Tdr0z>
.
|
@cartazio, the fast way to traverse an array is to
We'd like |
I'm not terribly familiar with Compose, could you walk me through an example? |
also where does Compose live? |
hrmm if this is the correct defintion of compose
wouldn't just require PrimMonad just one of these? |
hrmmm, that makes me think that we can't have an instance for compose, because there should only be one primonad in the stack ... i think? |
(something something global approximate linearity of state token) |
i guess i'm perhaps not understnding why Compose the data type/monad enters into this, but i'll have to look at more details |
Not even compositions of pure monads are necessarily monads. As my PR
shows, we can do good things for a lot of transformer stacks built on ST
and IO. Andrew has been working on an idea for stacks built on Identity,
Either, and Maybe (and perhaps even (a,)), but it's not ready yet. Compose
is a generally useful way to construct Applicatives, which people certainly
use with traverse, but I don't know if we'll be able to optimize for it or
not.
…On Fri, Apr 27, 2018, 5:45 PM Carter Tazio Schonwald < ***@***.***> wrote:
(something something global approximate linearity of state token)
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_RalzTkE83YEyH1yLdW5ZDNst80mks5ts5GAgaJpZM4Tdr0z>
.
|
The composition law for Traversable does seem to suggest we can probably do
something smart about Compose, actually. We know that
traverse
<http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Traversable.html#v:traverse>
(Compose
. fmap
<http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Functor.html#v:fmap>
g
. f) = Compose . fmap
<http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Functor.html#v:fmap>
(traverse
<http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Traversable.html#v:traverse>
g)
. traverse
<http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Traversable.html#v:traverse>
f
In particular,
traverse (Compose . f) = Compose . fmap sequenceA . traverse f
So we can turn one traversal into two, which sounds bad but is probably
actually good. For *pure* Applicatives, I conjecture that we can also turn
two traversals into one efficient one. Anyway, that's the start of a
thought in that direction. Still need to think it through a bit more.
…On Fri, Apr 27, 2018, 6:01 PM David Feuer ***@***.***> wrote:
Not even compositions of pure monads are necessarily monads. As my PR
shows, we can do good things for a lot of transformer stacks built on ST
and IO. Andrew has been working on an idea for stacks built on Identity,
Either, and Maybe (and perhaps even (a,)), but it's not ready yet. Compose
is a generally useful way to construct Applicatives, which people certainly
use with traverse, but I don't know if we'll be able to optimize for it or
not.
On Fri, Apr 27, 2018, 5:45 PM Carter Tazio Schonwald <
***@***.***> wrote:
> (something something global approximate linearity of state token)
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <#142 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ABzi_RalzTkE83YEyH1yLdW5ZDNst80mks5ts5GAgaJpZM4Tdr0z>
> .
>
|
WIP. I still need to handle
SmallArray
. I also need to make this work withEither
, but the backwards-compatibility story there is more annoying because of the historical absence ofExceptT
. I also want to do this forState
. Probably notWriter
though since it has abysmal performance anyway.