Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to make Traversal an instance of IsString

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!

like image 202
Pavel Avatar asked Dec 29 '25 15:12

Pavel


1 Answers

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)
like image 96
user2407038 Avatar answered Jan 01 '26 07:01

user2407038



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!