<div dir="auto">You can also sift monomorphic containers using my class, which should probably be called MonoSiftable.<div dir="auto"><br></div><div dir="auto">data IntList = Cons !Int IntList | Nil</div><div dir="auto"><br></div><div dir="auto">instance Siftable Int IntList where</div><div dir="auto">  sift _ Nil = Nil</div><div dir="auto">  sift p (Cons x xs)</div><div dir="auto">    | p x = Cons x (sift p xs)</div><div dir="auto">    | otherwise = sift p xs</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Dec 3, 2016 2:17 PM, "David Menendez" <<a href="mailto:dave@zednenem.com">dave@zednenem.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">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><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_-3201800365505634120m_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><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="m_-3201800365505634120gmail_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/~<wbr>zednenem/</a>></div>
</div></div>
</blockquote></div></div>