title: My use of Haskell's Text.JSON considered ugly?
body: <p>What I am trying to do is <strong>really simple</strong>. </p>
  
  <p>I'd like to convert the following JSON, which I'm getting from an external source:</p>
  
  <pre><code>[{"symbol": "sym1", "description": "desc1"}
   {"symbol": "sym1", "description": "desc1"}]
  </code></pre>
  
  <p>into the following types:</p>
  
  <pre><code>data Symbols = Symbols [Symbol]
  type Symbol  = (String, String)
  </code></pre>
  
  <p>I ended up writing the following code using Text.JSON:</p>
  
  <pre><code>instance JSON Symbols where
    readJSON (JSArray arr) = either Error (Ok . Symbols) $ resultToEither (f arr [])
      where
        f ((JSObject obj):vs) acc = either Error (\x -&gt; f vs (x:acc)) $ resultToEither (g (fromJSObject obj) [])
        f [] acc                  = Ok $ reverse acc
        f _ acc                   = Error "Invalid symbol/description list"
  
        g ((name, JSString val):vs) acc = g vs ((name, fromJSString val):acc)
        g [] acc                        = valg acc
        g _ acc                         = Error "Invalid symbol/description record"
  
        valg xs = case (sym, desc) of
          (Nothing, _)            -&gt; Error "Record is missing symbol"
          (_, Nothing)            -&gt; Error "Record is missing description"
          (Just sym', Just desc') -&gt; Ok (sym', desc')
          where
            sym = lookup "symbol" xs
            desc = lookup "description" xs
  
    showJSON (Symbols syms) = JSArray $ map f syms
      where
        f (sym, desc) = JSObject $ toJSObject [("symbol", JSString $ toJSString sym),
                                               ("description", JSString $ toJSString desc)]
  </code></pre>
  
  <p>This has got to the the most inelegant Haskell I've ever written. <code>readJSON</code> just doesn't look right. Sure, <code>showJSON</code> is substantially shorter, but what is up with this <code>JSString $ toJSString</code> and <code>JSObject $ toJSObject</code> stuff I am forced to put in here? And <code>resultToEither</code>? </p>
  
  <p>Am I using Text.JSON wrong? Is there a better way?</p>
  
  <hr>
  
  <p>Okay this is more like it. I've gotten <code>readJSON</code> down to the following thanks to the clarifications and ideas from Roman and Grazer. At every point it will detect an incorrectly formatted JSON and output an error instead of throwing an exception.</p>
  
  <pre><code>instance JSON Symbols where
    readJSON o = fmap Symbols (readJSON o &gt;&gt;= mapM f)
      where
        f (JSObject o) = (,) &lt;$&gt; valFromObj "symbol" o &lt;*&gt; valFromObj "description" o
        f _            = Error "Unable to read object"
  </code></pre>