haskell / core-libraries-committee

95 stars 16 forks source link

Add `<$<` and `>$>` to Data.Functor #265

Closed BebeSparkelSparkel closed 6 months ago

BebeSparkelSparkel commented 6 months ago

<$< and >$> would be use useful functions to have exported from Data.Functor. There is already a precedence for this syntax with >=> so it would be intuitive for most.

I only see one conflict with the package configuration-tools.

infixr 4 <$<
(<$<) :: Functor f => (b -> c) -> (a -> f b) -> a -> f c

infixr 4 >$>
(>$>) :: Functor f => (a -> f b) -> (b -> c) -> a -> f c
mixphix commented 6 months ago

The implementations being,

(<$<) :: Functor f => (b -> c) -> (a -> f b) -> a -> f c
bc <$< afb = fmap bc . afb

(>$>) :: Functor f => (a -> f b) -> (b -> c) -> a -> f c
(>$>) = flip (<$<)

Yeah, I don't think so.

ocharles commented 6 months ago

It would be helpful to see some examples where these combinators help

BebeSparkelSparkel commented 6 months ago

@mixphix I don't appreciate your attitude. Especially, since this is basically the exact implementation of the useful infix functions <=< and >=> that are already in base shown below.

https://gitlab.haskell.org/ghc/ghc/-/blame/master/libraries/ghc-internal/src/GHC/Internal/Control/Monad.hs?ref_type=heads#L185

(>=>)       :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
f >=> g     = \x -> f x >>= g

(<=<)       :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
(<=<)       = flip (>=>)

Please elaborate on your rejection.

thielema commented 6 months ago

On Thu, 18 Apr 2024, mixphix wrote:

The implementations being,

(<$<) :: Functor f => (b -> c) -> (a -> f b) -> a -> f c (<$<) = (.)

(>$>) :: Functor f => (a -> f b) -> (b -> c) -> a -> f c (>$>) = flip (.)

Yeah, I don't think so.

The function (b -> c) is applied to the Functor element.

Bodigrim commented 6 months ago

I'd like to remind everyone to remain respectful to each other.

@BebeSparkelSparkel could you possibly explain why you find these combinators particularly useful? There are quite a few combinations of (.) and fmap possible, but apparently you feel that these two are more interesting than others. Is there a prior art (e. g., alternative preludes or helper libraries such as extra and MissingH)?

BebeSparkelSparkel commented 6 months ago

@ocharles It is useful for modifying the result of monadic composition. My specific case is

BB.lazyByteString <$< BL.hGet h . fromInteger

reading in n :: Integer bytes from a file and then wrapping it in a ByteString Builder.

It is also used in

Centril/TDA283-compiler-construction many examples

_sfType <$$> getStructDef (_tIdent typ) >>= mapM compileType >$> LStruct

oisdk/HaskAlgebra

simplify (SSum xs) = either id SSum $ (factorise <=< sort <$< diff . c extractConst . extractSum . map simplify) xs

chainweb-node Not really sure why they use it but they use it a lot.

BebeSparkelSparkel commented 6 months ago

@Bodigrim It is possible to use . and fmap together but if a function has arguments it becomes a bit messier

fmap (splitAt 5) . getLines
splitAt 5 <$< getLines

Basically it is good for concluding monaic composition.

Bodigrim commented 6 months ago

It is also used in futurice/futuLog#L25

Just to be clear, this one is (>$>) :: Functor f => (a -> f b) -> c -> a -> f c, different from your proposal.

chainweb-node Not really sure why they use it but they use it a lot.

I think they use Configuration.Utils.(<$<) :: Functor f => f (a -> b) -> (b -> c) -> f (a -> c), again different from what you propose.

It is possible to use . and fmap together but if a function has arguments it becomes a bit messier

fmap (splitAt 5) . getLines
splitAt <$< getLines

Sorry, I don't quite follow the example. I assume getLines is Handle -> IO [String], in which case fmap (splitAt 5) . getLines :: Handle -> IO ([String], [String]), but then splitAt <$< getLines is ill-typed.

BebeSparkelSparkel commented 6 months ago

@Bodigrim Sorry for not looking at those examples more closely and wasting your time, I'll review them more thoroughly and update it.

BebeSparkelSparkel commented 6 months ago

Thanks for all your comments. This seems to be a personally useful function and not a community demanded function.

github search for this