<div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>That’s it. These two rules alone are enough to eliminate the redundant<br>
tupling. Now the optimized version of `mapMaybeSF` is beautiful!</div></blockquote><div><br></div><div>Beautiful indeed! That's wonderful to hear. Good luck messing about with your FRP framework!</div><div><br></div><div>Sebastian<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Am Sa., 4. Apr. 2020 um 03:45 Uhr schrieb Alexis King <<a href="mailto:lexi.lambda@gmail.com">lexi.lambda@gmail.com</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
I fiddled with alternative representations for a while and didn’t make<br>
any progress—it was too easy to end up with code explosion in the<br>
presence of any unknown calls—but I seem to have found a RULES-based<br>
approach that works very well on the examples I’ve tried. It’s quite<br>
simple, which makes it especially appealing!<br>
<br>
I started by defining a wrapper around the `SF` constructor to attach<br>
rules to:<br>
<br>
    mkSF :: (a -> s -> Step s b) -> s -> SF a b<br>
    mkSF = SF<br>
    {-# INLINE CONLIKE [1] mkSF #-}<br>
<br>
I  then changed the definitions of (.), (***), (&&&), (+++), and (&&&)<br>
to use `mkSF` instead of `SF`, but I left the other methods alone, so<br>
they just use `SF` directly. Then I defined two rewrite rules:<br>
<br>
    {-# RULES<br>
    "mkSF @((), _)" forall f s. mkSF f ((), s) =<br>
      SF (\a s1 -> case f a ((), s1) of Step ((), s2) b -> Step s2 b) s<br>
    "mkSF @(_, ())" forall f s. mkSF f (s, ()) =<br>
      SF (\a s1 -> case f a (s1, ()) of Step (s2, ()) b -> Step s2 b) s<br>
    #-}<br>
<br>
That’s it. These two rules alone are enough to eliminate the redundant<br>
tupling. Now the optimized version of `mapMaybeSF` is beautiful!<br>
<br>
    mapMaybeSF = \ @ a @ b f -> case f of { SF @ s f2 s2 -><br>
      SF (\ a1 s1 -> case a1 of {<br>
           Nothing -> case s1 of dt { __DEFAULT -> Step dt Nothing }<br>
           Just x -> case f2 x s1 of {<br>
             Step s2' c1 -> Step s2' (Just c1) }})<br>
         s2 }<br>
<br>
So unless this breaks down in some larger situation I’m not aware of, I<br>
think this solves my problem without the need for any fancy SpecConstr<br>
shenanigans. Many thanks to you, Sebastian, for pointing me in the right<br>
direction!<br>
<br>
Alexis</blockquote></div>