I want to use string literal as Traversal, but I am a bit lost in types. Is it possible to create this instance?
import Control.Lens
import Data.Aeson
import Data.Aeson.Lens
import Data.String
import Data.Default
{- Having:
key' :: AsValue t => Text -> Traversal' t (Maybe Value)
_JSON :: (ToJSON a, FromJSON a) => Traversal' t a
-}
instance (AsValue t, FromJSON v, ToJSON v, Default v) => IsString (Traversal' t v) where
fromString k = key' (fromString k) . non (toJSON def) . _JSON
To achieve something like this inside State monad:
"some-key" .= (3 :: Int)
Problem with universally quantified type instances. Thanks!
I couldn't get your code to compile, but that shouldn't matter. I assume that you have a function of type
fromStringTraversal :: (AsValue t, FromJSON v, ToJSON v, Default v)
=> String -> Traversal' t v
fromStringTraversal = undefined
Then to write your instance, simply inline the definition of Traversal' into the instance head. This works because any type variables in an instance are universally quantified over implicitly anyways.
{-# LANGUAGE RankNTypes, FlexibleInstances, GADTs #-}
instance (a ~ a', b ~ b', AsValue b, Default a, FromJSON a, ToJSON a, Applicative f)
=> IsString ((a -> f a') -> b -> f b') where
fromString = fromStringTraversal
The a ~ a', b ~ b' constraints could be moved from the context to the instance head, but this way gives better type inference. Then
{-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction #-}
-- Infered type:
-- test :: (AsValue s, MonadState s m) => m ()
test = "some-key" .= (3 :: Int)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With