-
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, `-fshow-docs-of-hole-fits` 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 non-empty.-} 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, right-associative 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 higher-order situations, such as @'map' ('$' 0) xs@, or @'Data.List.zipWith' ('$') fs xs@. Note that @($)@ is levity-polymorphic in its result type, so that foo $ True where foo :: Bool -> Int# is well-typed-} 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 -fno-show-provenance-of-hole-fits -fshow-docs-of-hole-fits #-} 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 -fmax-valid-hole-fits=N or -fno-max-valid-hole-fits) ``` 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