Big example + some detail on the pattern aliases
Getty Ritter
9 years ago
82 | 82 | Left "Found atom in cdr position" |
83 | 83 | ~~~~ |
84 | 84 | |
85 | These names and patterns can be quite long, so S-Cargot also exports | |
86 | several pattern synonyms that can be used both as expressions and | |
87 | in pattern-matches to make working with these types less verbose. | |
88 | These are each contained in their own module, as their names conflict | |
89 | with each other, so it's recommended to only import the type that | |
90 | you plan on working with: | |
91 | ||
92 | ~~~~.haskell | |
93 | *Data.SCargot.Repr.Basic> A 2 ::: A 3 ::: A 4 ::: Nil | |
94 | SCons (SCons (SCons (SAtom 2) (SAtom 3)) (SAtom 4)) SNil | |
95 | ~~~~ | |
96 | ||
97 | ~~~~.haskell | |
98 | *Data.SCargot.Repr.WellFormed> L [A 1,A 2,A 3] | |
99 | WFSList [WFSAtom 1,WFSAtom 2,WFSAtom 3] | |
100 | *Data.SCargot.Repr.WellFormed> let sexprSum (L xs) = sum (map sexprSum xs); sexprSum (A n) = n | |
101 | *Data.SCargot.Repr Data.SCargot.Repr.WellFormed> :t sexprSum | |
102 | sexprSum :: Num a => WellFormedSExpr a -> a | |
103 | *Data.SCargot.Repr.WellFormed> sexprSum (L [A 2, L [A 3, A 4]]) | |
104 | 9 | |
105 | ~~~~ | |
106 | ||
85 | 107 | ## Atom Types |
86 | 108 | |
87 | 109 | Any type can serve as an underlying atom type provided that it has |
142 | 164 | |
143 | 165 | ~~~~.haskell |
144 | 166 | import Data.Char (isDigit) |
167 | import Data.SCargot.General | |
145 | 168 | import Data.Text (Text) |
146 | 169 | import qualified Data.Text as T |
170 | ||
147 | 171 | |
148 | 172 | data Expr = Add Expr Expr | Num Int deriving (Eq, Show) |
149 | 173 | |
240 | 264 | *Data.SCargot.General> decode (asRich (vec mySpec)) "(1 [2 3])" |
241 | 265 | Right [RSList [RSAtom "1",RSList [RSAtom "2",RSAtom "3"]]] |
242 | 266 | ~~~~ |
267 | ||
268 | ## Putting It All Together | |
269 | ||
270 | Here is a final example which implements a limited arithmetic language | |
271 | with Haskell-style line comments and a special reader to understand hex | |
272 | literals: | |
273 | ||
274 | ~~~~.haskell | |
275 | data Op = Add | Sub | Mul | |
276 | data Atom = AOp Op | ANum Int | |
277 | data Expr = EOp Op Expr Expr | ENum Int deriving (Eq, Show) | |
278 | ||
279 | -- Conversions for our Expr type | |
280 | toExpr :: SExpr Atom -> Either String Expr | |
281 | toExpr (A (AOp op) ::: l ::: r ::: Nil) = EOp op <$> l <*> r | |
282 | toExpr (A (ANum n)) = pure (ENum n) | |
283 | toExpr sexpr = Left ("Invalid parse: " ++ show sexpr) | |
284 | ||
285 | fromExpr :: Expr -> SExpr Atom | |
286 | fromExpr (EOp op l r) = A (AOp op) ::: fromExpr l ::: fromExpr r ::: Nil | |
287 | fromExpr (ENum n) = ANum n | |
288 | ||
289 | -- Parser and serializer for our Atom type | |
290 | pAtom :: Parser Atom | |
291 | pAtom = ((ANum . read . T.unpack) <$> takeWhile1 isDigit) | |
292 | <|> (char "+" *> pure (AOp Add)) | |
293 | <|> (char "-" *> pure (AOp Sub)) | |
294 | <|> (char "*" *> pure (AOp Mul)) | |
295 | ||
296 | sAtom :: Atom -> Text | |
297 | sAtom (AOp Add) = "+" | |
298 | sAtom (AOp Sub) = "-" | |
299 | sAtom (AOp Mul) = "*" | |
300 | sAtom (ANum n) = T.pack (show n) | |
301 | ||
302 | -- Our comment syntax | |
303 | hsComment :: Parser () | |
304 | hsComment = string "--" >> takeWhile (/= '\n') >> return () | |
305 | ||
306 | -- Our custom reader macro | |
307 | hexReader :: Reader Atom | |
308 | hexReader _ = (Num . readHex . T.unpack) <$> takeWhile1 isHexDigit | |
309 | where isHexDigit c = isDigit c || c `elem` "AaBbCcDdEeFf" | |
310 | rd = readHex . head . fst | |
311 | ||
312 | -- Our final s-expression family | |
313 | myLangSpec :: SExprSpec Atom Expr | |
314 | myLangSpec | |
315 | = setComment hsComment -- set comment syntax to be Haskell-style | |
316 | $ addReader '#' hexReader -- add hex reader | |
317 | $ convertSpec toExpr fromExpr -- convert final repr to Expr | |
318 | $ mkSpec pAtom sAtom -- create spec with Atom type | |
319 | ~~~~ | |
320 | ||
321 | Keep in mind that you often won't need to write all this by hand, | |
322 | as you can often use a variety of built-in atom types, reader | |
323 | macros, comment types, and representations, but it's a useful | |
324 | illustration of all the options that are available to you should | |
325 | you need them! |