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

[JsonObject JsonValue] doesn't act like a list in all instances #35

Closed
jhickner opened this issue Nov 4, 2012 · 5 comments
Closed

[JsonObject JsonValue] doesn't act like a list in all instances #35

jhickner opened this issue Nov 4, 2012 · 5 comments
Labels

Comments

@jhickner
Copy link

jhickner commented Nov 4, 2012

I was expecting the result of findArray "foo" json to act like a list. It does sometimes, but not in all instances, leading to some confusing situations.

For instance, this doesn't work:

json = extract res
children = (findArray "children" . findObject "data") json
urls = map (findString "url" . findObject "data") children

urls ends up as a list of empty lists.

It seems the only way to get at the contents of the list in children is by destructuring, as in the flickr search demo. Other list operations like head children don't work either.

@evancz
Copy link
Member

evancz commented Nov 4, 2012

Can you show me the JSON object you are working with? findString returns an empty string (i.e. empty list) when the key is not found. Same with findArray which returns an empty list when the key is not found.

@jhickner
Copy link
Author

jhickner commented Nov 4, 2012

The json I'm testing with is the result returned from http://www.reddit.com/r/cinemagraphs/hot.json. Which I've downloaded and named downloaded.json.

Here's my test code:

import HTTP
import JSON

redditURL = "downloaded.json"

extract res = 
  case res of
  { Success str -> JSON.fromString str
  ; _           -> empty }

getUrls res = 
  let { json = extract res
      ; children = findArray "children" . findObject "data" $ json
      ; urls = map (findString "url" . findObject "data") children
      }
  in urls

main = lift (plainText . show) . lift getUrls . send . constant $ get redditURL

I'm just using plainText to print the result. It prints as:

[[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]

The format of the json is like this (with a bunch elided):

{
  "data":  {
    "children: [
      {"data": {"url": some url}},
      {"data": {"url": some url}},
      {"data": {"url": some url}},
      {"data": {"url": some url}},
    ]
  }
}

@evancz
Copy link
Member

evancz commented Nov 4, 2012

Ok, this is actually a bug in the type checker. The program you sent should have thrown a type error at compile time, so I'll look into what is going on.

The issue was that findObject :: String -> JsonObject JsonValue -> JsonObject was given a JsonValue as its second argument. JsonValue has a constructor JsonObject (JsonObject JsonValue), meaning that you have to extract the actual object. The first JsonObject is a type constructor and the second is a type.

This level of indirection is needed so that JsonNull, (JsonNumber 4) and JsonObject empty can all have the same type without all being valid arguments to things like findObject and findArray.

This should work:

import HTTP
import JSON

redditURL = "downloaded.json"

extract res = 
  case res of
  { Success str -> JSON.fromString str
  ; _           -> empty }

valueToObj v = case v of { JsonObject obj -> obj ; _ -> empty }

getUrls res = 
  let { json = extract res
      ; children = findArray "children" . findObject "data" $ json
      ; urls = map (findString "url" . findObject "data" . valueToObj) children
      }
  in urls

main = lift (flow down . map asText) . lift getUrls . sendGet $ constant redditURL

By the way, this is totally awesome! I had it output everything as images and it was really cool :D

You might be interested in something like this:

groups n lst =
  case lst of
  { [] -> [] ; x:xs -> take n lst : groups n (drop n lst) }

tile w tiles =
  flow down . intersperse (spacer 10 10) . map (flow right) $ groups (w `div` tileSize) tiles

@jhickner
Copy link
Author

jhickner commented Nov 4, 2012

Thanks! Wow, I hadn't messed much with the flow stuff yet! So coo!

@jhickner jhickner closed this as completed Nov 4, 2012
@evancz
Copy link
Member

evancz commented Nov 4, 2012

No problem!

See the other issue on fittedImage. If you do that fix, try adding replacing main with:

main = lift (flow down . map (fittedImage 300 200)) . lift getUrls . sendGet $ constant redditURL

Again, very cool idea! I'd love to see what it ends up looking like!

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

No branches or pull requests

2 participants