
Matthías Páll Gissurarson authored
One issue with valid hole fits is that the function names can often be opaque for the uninitiated, such as `($)`. This diff adds a new flag, `fshowdocsofholefits` that adds the documentation of the identifier in question to the message, using the same mechanism as the `:doc` command. As an example, with this flag enabled, the valid hole fits for `_ :: [Int] > Int` will include: ``` Valid hole fits include head :: forall a. [a] > a {^ Extract the first element of a list, which must be nonempty.} with head @Int (imported from ‘Prelude’ (and originally defined in ‘GHC.List’)) ``` And one of the refinement hole fits, `($) _`, will read: ``` Valid refinement hole fits include ... ($) (_ :: [Int] > Int) where ($) :: forall a b. (a > b) > a > b {^ Application operator. This operator is redundant, since ordinary application @(f x)@ means the same as @(f '$' x)@. However, '$' has low, rightassociative binding precedence, so it sometimes allows parentheses to be omitted; for example: > f $ g $ h x = f (g (h x)) It is also useful in higherorder situations, such as @'map' ('$' 0) xs@, or @'Data.List.zipWith' ('$') fs xs@. Note that @($)@ is levitypolymorphic in its result type, so that foo $ True where foo :: Bool > Int# is welltyped} with ($) @'GHC.Types.LiftedRep @[Int] @Int (imported from ‘Prelude’ (and originally defined in ‘GHC.Base’)) ``` Another example of where documentation can come in very handy, is when working with the `lens` library. When you compile ``` {# OPTIONS_GHC fnoshowprovenanceofholefits fshowdocsofholefits #} module LensDemo where import Control.Lens import Control.Monad.State newtype Test = Test { _value :: Int } deriving (Show) value :: Lens' Test Int value f (Test i) = Test <$> f i updTest :: Test > Test updTest t = t &~ do _ value (1 :: Int) ``` You get: ``` Valid hole fits include (#=) :: forall s (m :: * > *) a b. MonadState s m => ALens s s a b > b > m () {^ A version of ('Control.Lens.Setter..=') that works on 'ALens'.} with (#=) @Test @(StateT Test Identity) @Int @Int (<#=) :: forall s (m :: * > *) a b. MonadState s m => ALens s s a b > b > m b {^ A version of ('Control.Lens.Setter.<.=') that works on 'ALens'.} with (<#=) @Test @(StateT Test Identity) @Int @Int (<*=) :: forall s (m :: * > *) a. (MonadState s m, Num a) => LensLike' ((,) a) s a > a > m a {^ Multiply the target of a numerically valued 'Lens' into your 'Monad''s state and return the result. When you do not need the result of the multiplication, ('Control.Lens.Setter.*=') is more flexible. @ ('<*=') :: ('MonadState' s m, 'Num' a) => 'Lens'' s a > a > m a ('<*=') :: ('MonadState' s m, 'Num' a) => 'Control.Lens.Iso.Iso'' s a > a > m a @} with (<*=) @Test @(StateT Test Identity) @Int (<+=) :: forall s (m :: * > *) a. (MonadState s m, Num a) => LensLike' ((,) a) s a > a > m a {^ Add to the target of a numerically valued 'Lens' into your 'Monad''s state and return the result. When you do not need the result of the addition, ('Control.Lens.Setter.+=') is more flexible. @ ('<+=') :: ('MonadState' s m, 'Num' a) => 'Lens'' s a > a > m a ('<+=') :: ('MonadState' s m, 'Num' a) => 'Control.Lens.Iso.Iso'' s a > a > m a @} with (<+=) @Test @(StateT Test Identity) @Int (<=) :: forall s (m :: * > *) a. (MonadState s m, Num a) => LensLike' ((,) a) s a > a > m a {^ Subtract from the target of a numerically valued 'Lens' into your 'Monad''s state and return the result. When you do not need the result of the subtraction, ('Control.Lens.Setter.=') is more flexible. @ ('<=') :: ('MonadState' s m, 'Num' a) => 'Lens'' s a > a > m a ('<=') :: ('MonadState' s m, 'Num' a) => 'Control.Lens.Iso.Iso'' s a > a > m a @} with (<=) @Test @(StateT Test Identity) @Int (<<*=) :: forall s (m :: * > *) a. (MonadState s m, Num a) => LensLike' ((,) a) s a > a > m a {^ Modify the target of a 'Lens' into your 'Monad''s state by multipling a value and return the /old/ value that was replaced. When you do not need the result of the operation, ('Control.Lens.Setter.*=') is more flexible. @ ('<<*=') :: ('MonadState' s m, 'Num' a) => 'Lens'' s a > a > m a ('<<*=') :: ('MonadState' s m, 'Num' a) => 'Iso'' s a > a > m a @} with (<<*=) @Test @(StateT Test Identity) @Int (Some hole fits suppressed; use fmaxvalidholefits=N or fnomaxvalidholefits) ``` Which allows you to see at a glance what opaque operators like `(<<*=)` and `(<#=)` do. Reviewers: bgamari, sjakobi Reviewed By: sjakobi Subscribers: sjakobi, alexbiehl, rwbarton, thomie, carter Differential Revision: https://phabricator.haskell.org/D4848
c4d98341