Opened 19 months ago
Closed 19 months ago
#14855 closed bug (invalid)
Implementation of liftA2 for Const has high arity
Reported by: | lyxia | Owned by: | |
---|---|---|---|
Priority: | normal | Milestone: | |
Component: | libraries/base | Version: | 8.2.2 |
Keywords: | Cc: | lyxia | |
Operating System: | Unknown/Multiple | Architecture: | Unknown/Multiple |
Type of failure: | Runtime performance bug | Test Case: | |
Blocked By: | Blocking: | ||
Related Tickets: | Differential Rev(s): | ||
Wiki Page: |
Description (last modified by )
instance Monoid m => Applicative (Const m) where pure _ = Const mempty liftA2 _ (Const x) (Const y) = Const (x `mappend` y) (<*>) = coerce (mappend :: m -> m -> m)
https://hackage.haskell.org/package/base-4.10.1.0/docs/src/Data.Functor.Const.html#line-69
(<*>)
is implemented with a coerce
but liftA2
isn't. Would the following not have better inlining behavior?
liftA2 _ = coerce (mappend :: m -> m -> m)
Going further, should the unused argument also be moved to the RHS? What about pure
? What are the pros and cons compared to this other alternative:
pure = \_ -> Const mempty liftA2 = \_ -> coerce (mappend :: m -> m -> m)
This came up while implementing Applicative
for K1
in phab:D4447. K1
is essentially the same type as Const
and thus their instances should be identical for the sake of consistency. But it's not clear to me whether Const
's Applicative
instance is already optimal. Is it?
Change History (6)
comment:1 Changed 19 months ago by
Cc: | lyxia added |
---|
comment:2 Changed 19 months ago by
Description: | modified (diff) |
---|
comment:3 Changed 19 months ago by
Description: | modified (diff) |
---|
comment:4 Changed 19 months ago by
comment:5 Changed 19 months ago by
The Core looks different when the Monoid
remains abstract, but the same if it is specialized. So there is some optimization that makes it fine in the end.
Example with abstract Monoid
:
{-# LANGUAGE ScopedTypeVariables #-} module W where import Data.Coerce import Data.Functor.Const xyz, abc :: forall x a b c. Monoid x => (a -> b -> c) -> Const x a -> Const x b -> Const x c xyz _ (Const a) (Const b) = Const (mappend a b) abc _ = coerce (mappend :: x -> x -> x)
Core:
-- RHS size: {terms: 12, types: 24, coercions: 10, joins: 0/0} xyz1 xyz1 = \ @ x_a10q @ a_a10r @ b_a10s @ c_a10t $dMonoid_a10v _ ds1_d11x ds2_d11y -> mappend $dMonoid_a10v (ds1_d11x `cast` <Co:5>) (ds2_d11y `cast` <Co:5>) -- RHS size: {terms: 1, types: 0, coercions: 37, joins: 0/0} xyz xyz = xyz1 `cast` <Co:37> -- RHS size: {terms: 8, types: 14, coercions: 0, joins: 0/0} abc1 abc1 = \ @ x_a105 @ a_a106 @ b_a107 @ c_a108 $dMonoid_a10a _ -> mappend $dMonoid_a10a -- RHS size: {terms: 1, types: 0, coercions: 39, joins: 0/0} abc abc = abc1 `cast` <Co:39>
comment:6 Changed 19 months ago by
Resolution: | → invalid |
---|---|
Status: | new → closed |
I think you'll get the same code in all these cases, but you could
-ddump-simpl
to check.