<div dir="ltr">On Sat, Dec 3, 2016 at 12:50 AM, David Feuer <span dir="ltr"><<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span class=""><div class="gmail_extra" dir="auto"><div class="gmail_quote">On Dec 2, 2016 6:14 PM, "David Menendez" <<a href="mailto:dave@zednenem.com" target="_blank">dave@zednenem.com</a>> wrote:<blockquote class="m_6718120113580028189m_-742088320925499526quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>A while back, I found myself deriving this class:</div><div><br></div><div><div><div> class Functor f => Siftable f where</div><div> siftWith :: (a -> Maybe b) -> f a -> f b</div><div> sift :: (a -> Bool) -> f a -> f a</div><div> sift f = siftWith (\a -> if f a then Just a else Nothing)</div></div></div></div></div></div></blockquote></div></div><div dir="auto"><br></div></span><div dir="auto">I would expect several classes, corresponding to different methods of Witherable:</div><div dir="auto"><br></div><div dir="auto">class Siftable a m | m -> a where</div><div dir="auto"> sift :: (a -> Bool) -> m -> m</div><div dir="auto"> default sift :: SiftWithable f => (a -> Bool) -> f a -> f a</div><div dir="auto"> sift p = siftWith (\x -> x <$ guard (p x))</div><div dir="auto"><br></div><div dir="auto">class Functor f => SiftWithable f where</div><span class=""><div dir="auto"> siftWith :: (a -> Maybe b) -> f a -> f b</div><div dir="auto"><br></div></span><div dir="auto">class Siftable a m => SiftableA a m where</div><div dir="auto"> siftA :: Applicative g => (a -> g Bool) -> m -> g m</div><div dir="auto"> default siftA :: (SiftWithAAble f, Applicative g) => (a -> g Bool) -> f a -> g (f a)</div><div dir="auto"> siftA p = siftWithA (\x -> (x <$) . guard <$> p x)</div><div dir="auto"><br></div><div dir="auto">class (Traversable f, SiftWithAble f) => SiftWithAAble f where</div><div dir="auto"> siftWithA :: Applicative g => (a -> g (Maybe b)) -> f a -> g (f a)</div><div class="gmail_extra" dir="auto"></div></div>
</blockquote></div><div class="gmail_extra"><br></div>Yes, sift is more general than siftWith (which I should have called siftMap, in hindsight). But, so far as I know, the only things you can define sift for but not siftWith are sets and set-like things.</div><div class="gmail_extra"><br></div><div class="gmail_extra">At the time, I had also rejected sift by itself because I couldn’t think of any laws, but now that I look at it again, I guess they would be:</div><div class="gmail_extra"><br></div><div class="gmail_extra"> sift (const True) = id</div><div class="gmail_extra"> sift (\x -> p x && q x) = sift q . sift p</div><div class="gmail_extra"><br></div><div class="gmail_extra">I think those would make sift a monoid homomorphism.</div><div class="gmail_extra"><br></div><div class="gmail_extra">These still allow some weird instances, like sift _ = id, or something like this:</div><div class="gmail_extra"><br></div><div class="gmail_extra"> newtype Weird a = Map a Bool</div><div class="gmail_extra"><br></div><div class="gmail_extra"> instance Ord a => Siftable a (Weird a) where</div><div class="gmail_extra"> sift p (Weird m) = Weird (Map.union (Map.updateMin (const False) yes) no)</div><div class="gmail_extra"> where</div><div class="gmail_extra"> (yes, no) = Map.partitionWithKey (const . p) m</div><div class="gmail_extra"><div><br></div><div>I imagine it isn’t worth making the laws tighter to forbid this.</div><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">Dave Menendez <<a href="mailto:dave@zednenem.com" target="_blank">dave@zednenem.com</a>><br><<a href="http://www.eyrie.org/~zednenem/" target="_blank">http://www.eyrie.org/~zednenem/</a>></div>
</div></div>