Open ratherforky opened 5 months ago
👍 I'd happily accept a PR for improving performance. Bonus points for a benchmark that actually shows the improvement.
I wonder if it would be sufficient to change how these operators are defined. The current definitions are perhaps overly verbose.
-- current
x |> f = apply x f
f <| x = apply x f
apply x f = f x
f .> g = compose f g
g <. f = compose f g
compose f g x = g (f x)
x !> f = apply' x f
f <! x = apply' x f
apply' x f = seq x (apply x f)
-- could be
(|>) = apply
(<|) = flip apply
apply = (Data.Function.&)
-- or flip ($)
-- neither (&) nor flip have INLINE pragmas
(.>) = compose
(<.) = flip compose
compose = (Control.Category.>>>)
-- or flip (.)
-- "Note [INLINE on >>>]" https://hackage.haskell.org/package/base-4.19.1.0/docs/src/Control.Category.html#line-82
(!>) = apply'
(<!) = flip apply'
apply' = flip ($!)
I love this library and use it in basically every Haskell project, I just have one quibble: inlining
In
Prelude
, the source code for(.)
is:But
(.>)
,(<.)
,(|>)
etc. in Flow don't have any inline pragmas. I only checked this because(|>)
showed up as a non-zero cost centre in some code I was profiling and I was surprised.Changing the library to inline nicely should be fairly straightforward and I'd be happy to make a pull request for it. It'd mostly be a case of adding inline pragmas for everything, with the biggest change being
compose f g x = g (f x)
tocompose f g = \x -> g (f x)
for the same reason(.)
is like that.[^1][^2][^1]: > Moreover, GHC will only inline the function if it is fully applied, where “fully applied” means applied to as many arguments as appear (syntactically) on the LHS of the function definition. [^2]: I only learned about this behaviour after asking r/haskell to explain some surprising performance of foldl' and patching it in base