Skip to content

Commit fefa4c5

Browse files
vrom911chshersh
andauthored
[#139] Add type-errors for LogAction instances (#169)
* [#139] Add type-errors for `LogAction` instances Resolves #139 * Update co-log-core/CHANGELOG.md Co-Authored-By: Dmitrii Kovanikov <[email protected]> * Update co-log-core/src/Colog/Core/Action.hs Co-Authored-By: Dmitrii Kovanikov <[email protected]> * Fix doctests Co-authored-by: Dmitrii Kovanikov <[email protected]>
1 parent 5c02005 commit fefa4c5

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

co-log-core/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ The change log is available [on GitHub][2].
77

88
* [#122](https://github.com/kowainik/co-log/issues/122):
99
Add the `separate` combinator.
10+
* [#139](https://github.com/kowainik/co-log/issues/139):
11+
Add (unrepresentable) `Functor` instance for `LogAction` with the custom type-error.
1012

1113
## 0.2.0.0 — May 5, 2019
1214

co-log-core/src/Colog/Core/Action.hs

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
{-# LANGUAGE CPP #-}
2-
{-# LANGUAGE Rank2Types #-}
1+
{-# LANGUAGE CPP #-}
2+
{-# LANGUAGE DataKinds #-}
3+
{-# LANGUAGE Rank2Types #-}
4+
{-# LANGUAGE TypeFamilies #-}
5+
{-# LANGUAGE TypeOperators #-}
6+
{-# LANGUAGE UndecidableInstances #-}
37

48
{- |
59
Copyright: (c) 2018-2020 Kowainik
@@ -62,10 +66,12 @@ module Colog.Core.Action
6266
import Control.Monad (when, (<=<), (>=>))
6367
import Data.Coerce (coerce)
6468
import Data.Foldable (fold, for_, traverse_)
69+
import Data.Kind (Constraint)
6570
import Data.List.NonEmpty (NonEmpty (..))
6671
import Data.Monoid (Monoid (..))
6772
import Data.Semigroup (Semigroup (..), stimesMonoid)
6873
import Data.Void (Void, absurd)
74+
import GHC.TypeLits (ErrorMessage (..), TypeError)
6975

7076
#if MIN_VERSION_base(4,12,0)
7177
import qualified Data.Functor.Contravariant as Contravariant
@@ -144,13 +150,68 @@ instance Applicative m => Monoid (LogAction m a) where
144150

145151
#if MIN_VERSION_base(4,12,0)
146152
instance Contravariant.Contravariant (LogAction m) where
153+
contramap :: (a -> b) -> LogAction m b -> LogAction m a
147154
contramap = cmap
148155
{-# INLINE contramap #-}
149156

157+
(>$) :: b -> LogAction m b -> LogAction m a
150158
(>$) = (Colog.Core.Action.>$)
151159
{-# INLINE (>$) #-}
152160
#endif
153161

162+
-- | For tracking usage of unrepresentable class instances of 'LogAction'.
163+
type family UnrepresentableClass :: Constraint
164+
where
165+
UnrepresentableClass = TypeError
166+
( 'Text "'LogAction' cannot have a 'Functor' instance by design."
167+
':$$: 'Text "However, you've attempted to use this instance."
168+
#if MIN_VERSION_base(4,12,0)
169+
':$$: 'Text ""
170+
':$$: 'Text "Probably you meant 'Contravariant' class instance with the following methods:"
171+
':$$: 'Text " * contramap :: (a -> b) -> LogAction m b -> LogAction m a"
172+
':$$: 'Text " * (>$) :: b -> LogAction m b -> LogAction m a"
173+
#endif
174+
)
175+
176+
{- | ⚠️__CAUTION__⚠️ This instance is for custom error display only.
177+
178+
'LogAction' is not supposed to have 'Functor' instance by design.
179+
180+
In case it is used by mistake, the user will see the following:
181+
182+
#if MIN_VERSION_base(4,12,0)
183+
184+
>>> fmap show logStringStdout
185+
...
186+
... 'LogAction' cannot have a 'Functor' instance by design.
187+
However, you've attempted to use this instance.
188+
...
189+
Probably you meant 'Contravariant' class instance with the following methods:
190+
* contramap :: (a -> b) -> LogAction m b -> LogAction m a
191+
* (>$) :: b -> LogAction m b -> LogAction m a
192+
...
193+
194+
195+
#else
196+
197+
>>> fmap show logStringStdout
198+
...
199+
... 'LogAction' cannot have a 'Functor' instance by design.
200+
However, you've attempted to use this instance.
201+
...
202+
203+
#endif
204+
205+
@since 0.2.1.0
206+
-}
207+
instance UnrepresentableClass => Functor (LogAction m) where
208+
fmap :: (a -> b) -> LogAction m a -> LogAction m b
209+
fmap _ _ = error "Unreachable Functor instance of LogAction"
210+
211+
(<$) :: a -> LogAction m b -> LogAction m a
212+
_ <$ _ = error "Unreachable Functor instance of LogAction"
213+
214+
154215
{- | Operator version of 'unLogAction'. Note that because of the types, something like:
155216
156217
@

0 commit comments

Comments
 (0)