You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
That is, the instance ToJSON (Maybe (Maybe Int)) is automatically defined because of ToJSON a => ToJSON (Maybe a) and ToJSON Int, but toJSON can't separate Nothing and Just Nothing.
I consider the converter should satisfy the following condition for any x:
fromJSON (toJSON x) ==Success x
In particular, toJSON must be an injective function.
However, the definition of toJSON in ToJSON (Maybe a) is not generally injective because toJSON (Just x) = toJSON x has a possibility of Null.
Therefore, I suggest two ways to improve the library to avoid this problem.
One way is to create a class that doesn't return 'Null'.
dataNotNullValue=NotNullObject!Object
| NotNullArray!Array
| NotNullString!Text
| NotNullNumber!Scientific
| NotNullBool!Boolderiving (Eq, Read, Typeable, Data, Generic)
-- Without 'Null' from 'Value'.fromNotNullValue::NotNullValue->Value
fromNotNullValue v =case v ofNotNullObject o ->Object o
NotNullArray a ->Array a
NotNullString s ->String s
NotNullNumber n ->Number n
NotNullBool b ->Bool b
-- Class of 'ToJSON' that doesn't return 'Null'.classToNotNullJSONawheretoNotNullJSON::a->NotNullValuetoNotNullEncoding::a->Encoding
toNotNullEncoding =E.value . fromNotNullValue . toNotNullJSON
-- Should define instances of 'ToNotNullJSON' on basic types.-- ExampleinstanceToNotNullJSONBoolwhere
toNotNullJSON =NotNullBool
toNotNullEncoding =E.bool
-- Other instances also can define like 'ToJSON'.instancetoNotNullJSONa=>toJSON (Maybea) where
toJSON Nothing=Null
toJSON (Just x) = fromNotNullValue $ toNotNullJSON x
-- 'toJSON (Just x)' cannot return 'Null' because 'toNotNullJSON x' is not 'Null'.
toEncoding Nothing= null_
toEncoding (Just x) = toNotNullEncoding x
This definition is not allow toJSON (Maybe (Maybe a)) because ToNotNullJSON (Maybe a) is not defined.
However, if it is needed, we can define it as Either keeping the injectivity.
Then, we can define FromJSON satisfying fromJSON . toJSON = Success as the follows:
notNullValue::a-> (NotNullValue->a) ->Value->a
notNullValue n _ Null= n
notNullValue _ f (Object o) = f $NotNullObject o
notNullValue _ f (Array a) = f $NotNullArray a
notNullValue _ f (String s) = f $NotNullString s
notNullValue _ f (Number n) = f $NotNullNumber n
notNullValue _ f (Bool b) = f $NotNullBool b
classFromNotNullJSONawhereparseNotNullJSON::NotNullValue->ParserainstanceFromNotNullJSONBoolwhere
parseNotNullJSON = parseJSON . fromNotNullValue
-- Other instances also can be defined like this.instanceFromNotNullJSONa=>FromJSON (Maybea) where
parseJSON = notNullValue (pureNothing) (\v ->Just<$> parseNotNullJSON v)
instanceFromNotNullJSONa=>FromNotNullJSON (Maybea) where
parseNotNullJSON (NotNullObject (H.toList -> [(key,value)]))
| key == nothing =pureNothing| key == just =Just<$> notNullValue err parseNotNullJSON value
wherenothing, just::Text
nothing ="Nothing"
just ="Just"
err =fail$"expected an object with a single property "++"where the property value should not be Null"
parseNotNullJSON _ =fail$"expected an object with a single property "++"where the property key should be either "++"\"Nothing\" or \"Just\""
But, this way should be needed a lot of code.
Another suggestion is to remove Null from Value but use Nothing :: Maybe Value as Null.
typeObject=HashMapText (MaybeValue)
typeArray=Vector (MaybeValue)
-- Remove 'Null' from 'Value'.dataValue=Object!Object
| Array!Array
| String!Text
| Number!Scientific
| Bool!Boolderiving (Eq, Read, Typeable, Data, Generic)
-- 'Null' is defined as 'Nothing' in 'Maybe Value'.nullValue::MaybeValue
nullValue =Nothing-- Rewrite instances of 'ToJSON' to 'ToValue' if these don't return 'Null'.classToValueawheretoValue::a->ValuetoValueEncoding::a->Encoding-- Instances that returns 'Null' are only defined as 'ToJSON'.classToJSONawheretoJSON::a->MaybeValuetoEncoding::a->Encoding-- 'ToValue' to 'ToJSON' is naturally defined.instance {-# OVERLAPPABLE #-} ToValuea=>ToJSONawhere
toJSON =Just.ToValue
toEncoding = toValueEncoding
-- 'ToJSON (Maybe a)' is also naturally defined.instanceToValuea=>ToJSON (Maybea) where
toJSON =(<$>) toValue
toEncoding =maybe null_ toValueEncoding
I recommend this way and would like to join this project.
The text was updated successfully, but these errors were encountered:
I find a bug as the follows.
That is, the instance
ToJSON (Maybe (Maybe Int))
is automatically defined because ofToJSON a => ToJSON (Maybe a)
andToJSON Int
, buttoJSON
can't separateNothing
andJust Nothing
.I consider the converter should satisfy the following condition for any
x
:In particular,
toJSON
must be an injective function.However, the definition of
toJSON
inToJSON (Maybe a)
is not generally injective becausetoJSON (Just x) = toJSON x
has a possibility ofNull
.Therefore, I suggest two ways to improve the library to avoid this problem.
One way is to create a class that doesn't return 'Null'.
This definition is not allow
toJSON (Maybe (Maybe a))
becauseToNotNullJSON (Maybe a)
is not defined.However, if it is needed, we can define it as
Either
keeping the injectivity.Then, we can define
FromJSON
satisfyingfromJSON . toJSON = Success
as the follows:But, this way should be needed a lot of code.
Another suggestion is to remove
Null
fromValue
but useNothing :: Maybe Value
asNull
.I recommend this way and would like to join this project.
The text was updated successfully, but these errors were encountered: