@hackage hedn0.2.0.0
EDN parsing and encoding
Installation
Tested Compilers
Dependencies (13)
- base >=4.9 && <4.13
- containers >=0.5.7 && <0.7
- deepseq >=1.4 && <2
- deriving-compat >=0.3.6 && <0.6
- megaparsec >=7.0 && <8
- parser-combinators >=1.0 && <2 Show all…
Dependents (4)
@hackage/ron-schema, @hackage/ron, @hackage/acme-everything, @hackage/hedn-functor
Haskell EDN
An EDN parsing and encoding library inspired by aeson.
Based on spec and hints published on GitHub.
Hackage: https://hackage.haskell.org/package/hedn
Stackage: https://www.stackage.org/package/hedn
Examples
AST
(#haskell/edn example/kitchensink ; tagged symbol
nil ; ugh..
\space ; character
"dynamic \"typing\"" ; string
{:numbers ; keyword
[42 ; integer
42.0 ; floating
] ; Vector
:bools
#{true, false} ; Set (with optional commas)
} ; Map
) ; List
import qualified Data.EDN as EDN
import qualified Data.Text.IO as Text
main = do
edn <- Text.readFile "example.edn"
value <- EDN.parseText "example.edn" edn
print value
NoTag
(List
[ Tagged "haskell" "edn" (Symbol "example" "kitchensink")
, NoTag Nil
, NoTag (Character ' ')
, NoTag (String "dynamic \"typing\"")
, NoTag
(Map
(fromList
[ ( NoTag (Keyword "bools")
, NoTag
(Set (fromList [ NoTag (Boolean False) , NoTag (Boolean True) ]))
)
, ( NoTag (Keyword "numbers")
, NoTag (Vec [ NoTag (Integer 42) , NoTag (Floating 42.0) ])
)
]))
])
Conversion
More examples in tests/Data/EDN/Class/Test.hs.
data Person = Person
{ personFirst :: Text
, personLast :: Text
} deriving (Eq, Show)
instance ToEDN Person where
toEDN Person{..} =
toEDNtagged "myapp" "Person" $ Map.fromList
[ (EDN.Keyword "first", toEDN personFirst)
, (EDN.Keyword "last", toEDN personLast)
]
instance FromEDN Person where
parseEDN = \case
EDN.Tagged "myapp" "Person" v -> Person
<$> EDN.mapGetKeyword "first" v
<*> EDN.mapGetKeyword "last" v
_ ->
fail "myapp/Person expected"
import qualified Data.EDN as EDN
import qualified Data.Text.IO as Text
main = Text.putStrLn $
encodeText (Person "Fred" "Mertz")
#myapp/Person {:first "Fred" :last "Mertz"}
Quasiquoter
Embed EDN AST literals with edn:
fredEDN = [edn|
#myapp/Person {:first "Fred" :last "Mertz"}
|]
Additionally there are QQs for untagged collections. They simply wrap the block in appropriate symbols.
- Lists,
()EDN.List (items :: [TaggedValue]) = [ednList| this is a list of symbols, commas are whitespace |] - Vectors,
[]EDN.Vec (items :: Vector TaggedValue) = [ednVec| 42 is #the/answer true |] - Sets,
#{}EDN.Set (items :: Set TaggedValue) = [ednSet| badger badger badger badger badger badger badger badger mushroom mushroom |] - Maps,
{}EDN.Map (dict :: Map TaggedValue TaggedValue) = [ednMap| :keywords "as you like it" or/symbols "I won't judge" #uuid "d748ab62-9cb1-41fb-b8dc-e23f3ffc5f9b" (tagged values, collections, anything goes) |]
EDN as DSL syntax
You can add quasiquoters for your values by specializing fromEDN QuasiQuoter.
Usual TH shenanigans apply. Define things in a separate module. Either
Data.Data.DataorLanguage.Haskell.TH.Syntax.Liftinstance required to convert values to Haskell AST.
module My.Data.QQ (myData) where
import Data.EDN.QQ (fromEDN)
import My.Data.Types (MyData)
myData :: QuasiQuoter
myData = fromEDN @MyData
module Main where
import My.Data.QQ (myData)
main :: IO ()
main = cobc
[myData|
{:identification-division
[#program/id hello]
:procedure-division
((display "Hello, world!"
end-display)
stop-run
)
}
|]