garyb / purescript-codec-argonaut

Bi-directional JSON codecs for argonaut
MIT License
38 stars 16 forks source link

Identity combinator #58

Open yaitskov opened 1 year ago

yaitskov commented 1 year ago

Argonaut library has functions to deal with lot of builtin types including Maybe, though I cannot find an option for Identity.

identity combinator, besides making the library more logically complete, has common usecase - a front-end application has a high kinded type to represent partial value for a complex type (structural editor) e.g.

data ValT f = Val (f Number)
data OpT f 
  = Const (f Val) 
  | Prod (f (OpT f)) (f (OpT f)) 
  | Sum (f (OpT f)) (f (OpT f)) 

Form validation deals with type OpM = OpT Maybe, but server expect a complete object, so type Op = Op Identity is going to be serialized to JSON.

valCodec :: CA.JsonCodec Val
valCodec = idCodec CA.number   
import Data.Identity (Identity (..))
import Data.Profunctor (dimap)

unIdentity :: ∀ a. Identity a -> a
unIdentity (Identity a) = a

idCodec :: ∀ a. CA.JsonCodec a -> CA.JsonCodec (Identity a)
idCodec = dimap unIdentity pure
garyb commented 1 year ago

We could add something for this, but it's so simple to write inline that I usually just do that. Two alternatives to dimap:

import Data.Profunctor (wrapIso)

valCodec = wrapIso Identity CA.number
import Data.Lens.Iso.Newtype (_Newtype)

valCodec = _Newtype CA.number

Or probably the better option is to use the coercible codec. I say "better" because it also allows you to name the type to help with debugging:

valCodec = CA.coercible "Val" CA.number