Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decoding different yaml types for a single node is tricky #43

Closed
AlistairB opened this issue Apr 20, 2020 · 5 comments
Closed

Decoding different yaml types for a single node is tricky #43

AlistairB opened this issue Apr 20, 2020 · 5 comments

Comments

@AlistairB
Copy link

In some cases you might have yaml like:

list-o-things:
  - "Im text"
  - 2
  - name: complex-case
    extra-info: stuff

In yaml / aeson that is pretty simple to handle:

newtype Thing = Thing Text

instance FromJSON Thing where
  parseJSON (String a) = pure $ Thing a
  parseJSON (Object v) =   -- v is a HashMap and quite easy to work with

In HsYAML there doesn't seem to ways to do this without getting deep into library internals.

instance FromYAML Thing where
  parseYAML (Scalar _ (SStr a)) = pure $ Thing a
  parseYAML (Mapping _ _ _) = -- withMap would be redundant, but how else to write the parser?
@vijayphoenix
Copy link
Collaborator

vijayphoenix commented Apr 20, 2020

@AlistairB You can use the Node type, which is an instance of FromYAML.
It is used to represent an arbitrary YAML AST.
For each yaml file you will get a single YAML Node.

For example:

decode1 "list-o-things:\n- 'Im text'\n- 2\n- name: complex-case\n  extra-info: stuff" :: Either (Pos,String) (Node Pos)

You get:

Right (Mapping (Pos {posByteOffset = 0, posCharOffset = 0, posLine = 1, posColumn = 0}) Just "tag:yaml.org,2002:map" (fromList [(Scalar (Pos {posByteOffset = 0, posCharOffset = 0, posLine = 1, posColumn = 0}) (SStr "list-o-things"),Sequence (Pos {posByteOffset = 15, posCharOffset = 15, posLine = 2, posColumn = 0}) Just "tag:yaml.org,2002:seq" [Scalar (Pos {posByteOffset = 17, posCharOffset = 17, posLine = 2, posColumn = 2}) (SStr "Im text"),Scalar (Pos {posByteOffset = 29, posCharOffset = 29, posLine = 3, posColumn = 2}) (SInt 2),Mapping (Pos {posByteOffset = 33, posCharOffset = 33, posLine = 4, posColumn = 2}) Just "tag:yaml.org,2002:map" (fromList [(Scalar (Pos {posByteOffset = 54, posCharOffset = 54, posLine = 5, posColumn = 2}) (SStr "extra-info"),Scalar (Pos {posByteOffset = 66, posCharOffset = 66, posLine = 5, posColumn = 14}) (SStr "stuff")),(Scalar (Pos {posByteOffset = 33, posCharOffset = 33, posLine = 4, posColumn = 2}) (SStr "name"),Scalar (Pos {posByteOffset = 39, posCharOffset = 39, posLine = 4, posColumn = 8}) (SStr "complex-case"))])])]))

@AlistairB
Copy link
Author

@vijayphoenix Thanks for the comment. I see that it is possible to handle my scenario, however it seems that using Node gets me fairly deep into library internals. aeson handles this case without requiring this. Perhaps this is simply HsYAML having a different focus to yaml ie. being more low level (and this can closed).

@vijayphoenix
Copy link
Collaborator

vijayphoenix commented Apr 20, 2020

@AlistairB Also, another solution is to use HsYAML-aeson.

If your YAML data can be converted to JSON, you could use
https://hackage.haskell.org/package/HsYAML-aeson-0.2.0.0/docs/Data-YAML-Aeson.html#g:2

@vijayphoenix
Copy link
Collaborator

If this helps, you can close the issue.

@AlistairB
Copy link
Author

Yeah I considered HsYAML-aeson but that adds more complexity which I would like to avoid. My code is operating in a low memory environment so #40 also impacts me, so I've decided to use yaml.

Anyway, it sounds like my usability issue is not considered a problem for HsYAML so I will close thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants