<div dir="auto"><div>The recursion is the first barrier. The whole thing ends up a loop breaker. Using `fix` fixes that, but it still doesn't fuse for some reason. After I sent this, I realized that foldl' is really the wrong thing, since that builds up a large Q action that, when run, produces the expression. The nicer thing is to use foldM within Q, and wrap mfix around that. I'm still not seeing fusion with that, and I wonder if that's because of the complexity of the Q type with its higher-rank constrained polymorphism and such.</div><div dir="auto"><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Thu, Sep 22, 2022, 1:56 PM Joachim Breitner <<a href="mailto:mail@joachim-breitner.de">mail@joachim-breitner.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<br>
Am Sonntag, dem 11.09.2022 um 19:05 -0400 schrieb David Feuer:<br>
> The template-haskell package has functions `tupE` and `tupP` for<br>
> building tuple expressions and patterns, respectively, but nothing<br>
> really similar for building tuple types. I came up with the version<br>
> below the other day:<br>
> <br>
> -- | Given a list of types, produce the type of a tuple of<br>
> -- those types. This is analogous to 'tupE' and 'tupP'.<br>
> --<br>
> -- @<br>
> -- tupT [[t|Int|], [t|Char|], [t|Bool]] = [t| (Int, Char, Bool) |]<br>
> -- @<br>
> tupT :: [Q Type] -> Q Type<br>
> tupT ts = n `seq` res<br>
>   where<br>
>     -- We build the expression with a thunk inside that will be filled in with<br>
>     -- the length of the list once that's been determined. This works<br>
>     -- efficiently (in one pass) because TH.Type is rather lazy.<br>
>     (res, n) = foldl' (\(acc, !k) ty -> ([t| $acc $ty |], k + 1))<br>
>                       (tupleT n, 0)<br>
>                       ts<br>
> <br>
> I strongly suspect this is quite fast enough in practice, but it's a<br>
> bit annoying that it won't participate in list fusion; tupT (map f xs)<br>
> will (lazily) generate an intermediate list. I wasn't able to convince<br>
> GHC to fuse it, short of a custom rewrite rule or two (tupT (build f)<br>
> = ..., tupT (augment f r = ...). Does anyone know if it's possible?<br>
<br>
Can you say why it would not fuse? It seems it could, if tupT inlines,<br>
and then you have foldl' applied to (map f xs), and at this point I<br>
would hope that fusion kicks in.<br>
<br>
Cheers,<br>
Joachim<br>
<br>
-- <br>
Joachim Breitner<br>
  <a href="mailto:mail@joachim-breitner.de" target="_blank" rel="noreferrer">mail@joachim-breitner.de</a><br>
  <a href="http://www.joachim-breitner.de/" rel="noreferrer noreferrer" target="_blank">http://www.joachim-breitner.de/</a><br>
<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
Only members subscribed via the mailman list are allowed to post.</blockquote></div></div></div>