I started using lens after watching this great talk: https://youtu.be/LBiFYbQMAXc
I’ve since then successfully made lens with very few lines of code for custom types. But I know very little about generic and overloaded labels. I encountered a problem when trying to make lens for these types (only showed the relevant ones):
data Chat = Chat
{ users :: Map Int User
, msgs :: [ MsgFromServer ]
, joinCount :: Int
, config :: Config
} deriving ( Generic )
data Config = Config
{ maxJoinCount :: Maybe Int
, expiry :: Expiry
, persist :: Bool
, sendHistory :: Bool
} deriving ( Generic )
instance FromJSON Config
data Expiry
= Empty
| MaxJoined
| Never
deriving ( Generic )
instance FromJSON Expiry
isMaxJoined :: Chat -> Bool
isMaxJoined chat =
case chat ^. #config . #maxJoinCount of
Just posInt ->
if chat ^. #joinCount == posInt then True
else False
_ -> False
I got 4 errors:
• No instance for (GHC.OverloadedLabels.IsLabel
“config” (b0 -> Chat -> Data.Functor.Const.Const (Maybe a0) Chat))
arising from the overloaded label ‘#config’
(maybe you haven’t applied a function to enough arguments?)
• In the first argument of ‘(.)’, namely ‘#config’
In the second argument of ‘(^.)’, namely ‘#config . #maxJoinCount’
In the expression: chat ^. #config . #maxJoinCount
|
77 | case chat ^. #config . #maxJoinCount of
^^^^^^^ |
---|
• No instance for (GHC.OverloadedLabels.IsLabel
"maxJoinCount"
((Maybe a0 -> Data.Functor.Const.Const (Maybe a0) (Maybe a0))
-> b0))
arising from the overloaded label ‘#maxJoinCount’
(maybe you haven't applied a function to enough arguments?)
• In the second argument of ‘(.)’, namely ‘#maxJoinCount’
In the second argument of ‘(^.)’, namely ‘#config . #maxJoinCount’
In the expression: chat ^. #config . #maxJoinCount
|
77 | case chat ^. #config . #maxJoinCount of
^^^^^^^^^^^^^ |
---|
• Ambiguous type variable ‘a0’ arising from a use of ‘==’
prevents the constraint ‘(Eq a0)’ from being solved.
Relevant bindings include posInt :: a0 (bound at src/Chat.hs:78:10)
prevents the constraint ‘(Eq a0)’ from being solved.
Relevant bindings include posInt :: a0 (bound at src/Chat.hs:78:10)
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance (Eq k, Eq a) => Eq (Map k a)
-- Defined in ‘Data.Map.Internal’
instance Eq Ordering -- Defined in ‘ghc-prim-0.6.1:GHC.Classes’
instance Eq ChatId -- Defined at src/Chat.hs:32:14
...plus 24 others
...plus 216 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the expression: chat ^. #joinCount == posInt
In the expression:
if chat ^. #joinCount == posInt then True else False
In a case alternative:
Just posInt -> if chat ^. #joinCount == posInt then True else False
|
79 | if chat ^. #joinCount == posInt then True
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
---|
• No instance for (GHC.OverloadedLabels.IsLabel
"joinCount" (Control.Lens.Getter.Getting a0 Chat a0))
arising from the overloaded label ‘#joinCount’
(maybe you haven't applied a function to enough arguments?)
• In the second argument of ‘(^.)’, namely ‘#joinCount’
In the first argument of ‘(==)’, namely ‘chat ^. #joinCount’
In the expression: chat ^. #joinCount == posInt
|
79 | if chat ^. #joinCount == posInt then True
| ^^^^^^^^^^
So everything worked before I added this new Config
type. And I’m most surprised that #joinCount
is somehow not working here.
I found out that if I move isMaxJoined
out of the src/Chat.hs
module where those types and lenses are defined, into src/Lib.hs
which actually uses it, the code will compile. But if I create a separate src/ChatUtils.hs
and move isMaxJoined
there, it somehow throws the same errors.
The resource online explaining generic and overloaded labels are too dense for me to comprehend. Can I get some directions?