-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add part(ition) and part(ition)ing to Filterable #45
Comments
You should make this a PR :) |
I'd sure like this! |
This can have surprising behavior with witherable/witherable/src/Witherable.hs Lines 306 to 309 in 187ca07
Now we're launching twice the missiles |
When you look at it without the newtype it isn't really surprising parting :: Filterable g => (a -> Either b c) ->
g a -> (g b, g c)
-- ^ ^ ^
-- duplicated, including f in g = Compose f g'
fmap . parting :: (Functor f, Filterable g) => (a -> Either b c) ->
f (g a) -> f (g b, g c)
-- ^ ^
-- not duplicated for outer f Of course this requires unwrapping Compose, and can't be rewrapped without another Compose V2 in the middle (where V2 a = a x a) indicating the duplicated component parting :: Filterable f => (a -> Either b c) -> f a %1 -> (f b, f c) |
To clarify, are there any objections to adding this? |
No objection from me |
OK, finally found some time to work on this. data Sum xs where
SL :: x -> Sum [x]
SR :: Sum xs -> Sum (a:xs)
absurdSum :: Sum [] -> a
absurdSum x = case x of {}
is :: Maybe a -> Bool
is (Just _) = True
is Nothing = False
sL :: Sum (x:xs) -> Maybe x
sL (SL x) = Just x
sL (SR _) = Nothing
sR :: Sum (x:xs) -> Maybe (Sum xs)
sR (SR x_) = Just x
sR (SL _) = Nothing
data Prod xs where
O :: Prod []
C :: x -> Prod xs -> Prod (x:xs)
class Filterable f => Part f xs where
part :: f (Sum (xs :: [Type])) -> (Prod (xs :: [Type]))
instance Filterable f => Part f [] where
part = fmap absurdSum
instance (Filterable f, Part f xs) => Part f (x:xs) where
part xs = filter (is.sL) xs `C` part (mapMaybe sR xs) Of course, this is starting to verge on scope creep. Especially considering |
That i.e. reinventing That's why I don't think Another argument is why not adding also
I don't see a good guideline why something should be in |
Perhaps exposing something like the composable folds of |
Also: the GADT
How? Could you sketch? |
I hadn't considered putting values into both functors, just divvying them up. It is pretty arbitrary seeing that maybe version, since you could have _ -> (Maybe a, Maybe b, ..., Maybe z), and it really is just a bunch of mapMaybes. class Functor f => Filterable f where
mapMaybe :: (a -> Maybe b) -> f a -> f b
-- rank 2 distributive, from rank2classes
class Distributive t where
cotraverse :: Functor m => (forall a. m (p a) -> f a) -> m (t p) -> t f
mapMaybes :: (Filterable f, Distributive t) => (a -> t Maybe) -> f a -> t f
mapMaybes f = cotraverse (mapMaybe id) . fmap f
-- example, mapMaybe to int char and a
data CustomTuple a f = CustomTuple { int :: f Int, char :: f Char, a :: f a }
instance Distributive (CustomTuple a) where
cotraverse h b = CustomTuple (h (fmap int b)) (h (fmap char b)) (h (fmap a b)) |
The idea was half-formed and doesn't quite hold up on further inspection. Basically thought we might be able to reify the maps arising from the particular Trying to find a different way to type what I'm suggesting here, you'd want so going by @Jashweii's implementation, we'd have genCatMaybes :: (Filterable f, Distributive t) => f (t Maybe) -> t f
genCatMaybes = cotraverse catMaybes |
Odds of that were pretty low! I dunno if there's an efficient way of doing this generally except maybe with representable. If it's not any more efficient it may as well be a free function assuming it's useful enough. |
@Jashweii I see, with {-# LANGUAGE DeriveGeneric #-}
{-# OPTIONS_GHC -Wall #-}
module Partition where
import GHC.Generics (Generic)
-- from hkd
-- https://hackage.haskell.org/package/hkd-0.1/docs/Data-HKD.html
import Data.HKD
class Partition f where
partition :: FRepeat r => (a -> r Maybe) -> f a -> r f
instance Partition [] where
partition _ [] = frepeat []
partition f (x:xs) = fzipWith maybeCons (f x) (partition f xs)
where
maybeCons Nothing ys = ys
maybeCons (Just y) ys = y : ys
-- an example
data HTriple a b c f = HTriple (f a) (f b) (f c)
deriving (Show, Generic)
instance FFunctor (HTriple a b c) where ffmap _ _ = error "not needed"
instance FZip (HTriple a b c) where fzipWith = gfzipWith
instance FRepeat (HTriple a b c) where frepeat = gfrepeat
justIf :: (a -> Bool) -> a -> Maybe a
justIf f x = if f x then Just x else Nothing
-- HTriple [1,3,5,7,9] [2,4,6,8,10] ["1","2","3","4","5","6","7","8","9","10"]
ex :: HTriple Int Int String []
ex = partition (\x -> HTriple (justIf odd x) (justIf even x) (Just (show x))) [1..10 :: Int] and this should be good if And EDIT: its next version is something like in https://github.com/ekmett/hkd/blob/main/hkd.cabal, so my opinion is that |
Makes sense for me. |
|
Ah right. It's getting late here, my mistake. |
@hseg, I'd call |
Addressing #21
The default implementation uses mapMaybe twice (mapMaybe and parting can both be expressed in terms of the other). By adding it as a method, lists, maps and other instances can avoid making two traversals.
Likewise indexed and applicative/traversal variants could be added.
The text was updated successfully, but these errors were encountered: