<p dir="ltr">I was wrong. It's possible to write the general safe merge function in Haskell 98, by replacing the GADT with a record of functions. Sorry for the confusion!</p>
<div class="gmail_extra"><br><div class="gmail_quote">On Aug 8, 2016 11:08 AM, "Edward Kmett" <<a href="mailto:ekmett@gmail.com" target="_blank">ekmett@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">You could always bury the GADT in an internal module with whatever super-general API you expose that uses it. ;)<div><br></div><div>Then I can have a sexy profunctor instance.<br><div><br></div><div>-Edward</div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Aug 8, 2016 at 10:55 AM, Ryan Trinkle <span dir="ltr"><<a href="mailto:ryan.trinkle@gmail.com" target="_blank">ryan.trinkle@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Ah, that sounds interesting!  I'm not really sure there's much value to exposing the GADT, so perhaps it would be better to keep it abstract.  Plus, you can always open it up later, but doing a deprecation cycle if you decide it needs to be abstract will be super painful.  So i guess I'd tend to think that abstract is the safer option.</div><div><div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Aug 8, 2016 at 10:28 AM, David Feuer <span dir="ltr"><<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><p dir="ltr">Thanks! One more question: should I export the GADT constructors, or just bindings for them? The (theoretical) advantage of the latter is that I can enforce equivalences</p>
<p dir="ltr">dropC == mapFilterC (\_ _ -> Nothing)</p>
<p dir="ltr">and</p>
<p dir="ltr">preserveC == mapFilterC (\_ v -> Just v)</p>
<p>I think this lets us write<br></p><p dir="ltr">instance Functor f => Functor (MergeTactic f k v) where<br>  fmap _ Drop = Drop<br>  fmap f Preserve = MapFilter (\_ -> Just . f)<br>  fmap f (MapFilter p) = MapFilter (\k x -> f <$> p k x)<br>  fmap f (TraverseFilter p) = TraverseFilter (\k x -> fmap f <$> p k x)</p><p dir="ltr">and I think this lets profunctors write</p><p dir="ltr"><br>instance Functor f => Profunctor (MergeTactic f k) where<br>  dimap _ _ Drop = Drop<br>  dimap f g Preserve = MapFilter (\_ -> Just . g . f)<br>  dimap f g (MapFilter p) = MapFilter (\k x -> g <$> p k (f x))<br>  dimap f g (TraverseFilter p) = TraverseFilter (\k x -> fmap g <$> p k (f x))<br><br></p><div><div><div class="gmail_extra"><br><div class="gmail_quote">On Aug 8, 2016 9:59 AM, "Ryan Trinkle" <<a href="mailto:ryan.trinkle@gmail.com" target="_blank">ryan.trinkle@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Wow, that looks great!  I wasn't expecting something that clean or that general.<div><br></div><div>The choice of INLINE or INLINABLE is above my pay grade, but I'm sure this will be a huge improvement either way!</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Aug 8, 2016 at 9:48 AM, David Feuer <span dir="ltr"><<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><p dir="ltr">Is this good? <a href="https://github.com/haskell/containers/pull/317/files#diff-52bcc964836f9c44f05804a0c2267321R1904" target="_blank">https://github.com/haskell/con<wbr>tainers/pull/317/files#diff-52<wbr>bcc964836f9c44f05804a0c2267321<wbr>R1904</a></p>
<p dir="ltr">Ryan: I worked out a general map combining function, with some help from Dan Doel and Cale, that I think gets most of what you'd want from such a thing without the horrors of mergeWithKey.</p>
<p dir="ltr">Both of you: I changed the Applicative actions to make sure they're entirely deterministic (going strictly in key order, interleaving actions associated with A-B, B-A, and A /\ B) without depending on tree balance. I decided that while it makes the most sense for the function to be in the middle, it's most convenient for it to be after the tactics, so I did that. If you disagree, let me know. Also, feedback on the type and constructor names would be great. Currently, the function is marked INLINE, like mergeWithKey. Should I mark it INLINABLE instead, and let users who want to be sure use an explicit `inline` call?</p>
</blockquote></div><br></div>
</blockquote></div></div>
</div></div></div>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div>
</blockquote></div></div>