1
votes

I'm new to Snap and Haskell. I am attempting to turn this output:

[("LDPNLNDQQFHUKIWZII",2191.12),("NLNDQQFHUKIWZIIXDC",2195.0696),("NZRAIEUALDPNLNDQQFH",2192.0503)]

into JSON. So I know the type is [(String, Double)], but that doesn't help me with the error message arising from GHCi when entering writeJSON [("LDPNLNDQQFHUKIWZII",2191.12),("NLNDQQFHUKIWZIIXDC",2195.0696),("NZRAIEUALDPNLNDQQFH",2192.0503)]:

No instance for (MonadSnap m0) arising from a use of `writeJSON' The type variable `m0' is ambiguous Possible fix: add a type signature that fixes these type variable(s) Note: there are several potential instances: instance MonadSnap m => MonadSnap (Control.Monad.Trans.Cont.ContT c m) -- Defined in `snap-core-0.9.5.0:Snap.Internal.Instances' instance (MonadSnap m, Control.Monad.Trans.Error.Error e) => MonadSnap (Control.Monad.Trans.Error.ErrorT e m) -- Defined in `snap-core-0.9.5.0:Snap.Internal.Instances' instance MonadSnap m => MonadSnap (Control.Monad.Trans.List.ListT m) -- Defined in `snap-core-0.9.5.0:Snap.Internal.Instances' ...plus 8 others In the expression: writeJSON x In an equation for `it': it = writeJSON x

I'm not married to the current data structure (I just created it to clump an amino acid sequence with its mass). Ideally I would get JSON data that looks like this:

{ "LDPNLNDQQFHUKIWZII":2191.12, "NLNDQQFHUKIWZIIXDC":2195.0696, "NZRAIEUALDPNLNDQQFH":2192.0503 }

The output, [("LDPNLNDQQFHUKIWZII",2191.12),("NLNDQQFHUKIWZIIXDC",2195.0696),("NZRAIEUALDPNLNDQQFH",2192.0503)], is calculated by a function that takes two pieces of input from the user: an original peptide sequence, and a weight (the program finds fragments from the peptide sequence that equal the entered weight).

Any help/direction is appreciated. Thanks!

ADDITIONAL INFORMATION:

I generated the app using snap init barebones. Here is what the handler looks like. I am getting the error at the writeJSON result line. I am intending on using the getParam lines, but to start I was just trying to get the JSON response.

possibleMatches :: Snap ()
possibleMatches = do
  peptideSequence <- getParam "peptide_sequence"
  weight          <- getParam "weight"
  let sequence = "V(3D)NK(3F)NKEXCNZRAIEUALDPNLNDQQFHUKIWZIIXDC"
  let weight = 2194.9
  let results = calculationResults weight sequence
  let result = take 1 [ seq | (seq,wt) <- results ]
  maybe (writeBS "must specify params in URL")
         writeJSON result

The error from the compiler is:

Couldn't match expected type `Maybe a0'
                with actual type `[([Char], Float)]'

So I need to figure out how to deal with Maybe. I'm reading on it but some help would be appreciated.

1
Where are the functions toJSNO and writeJSON coming from? - DiegoNolan
oh excuse me. the stack trace is correct, it's the writeJSON function coming from Snap.Extras.JSON. toJSON was another option I was investigating from the json package, Text.JSON (similarly, no luck). - Stuart Nelson
Can you put a bit more code? Is this in one of your handlers? It seems because the problem is you need to specify the instance of MonadSnap you are using but the compiler can't deduce it from the code you have. The default MonadSnap you'll be in if you just use when snap generates when you type snap init default would be Handler App App. If you've put this function in another monad it may be a problem. - DiegoNolan
Okay, I'll an idiot. You said you entered it to ghci. You need to say what the monad is. This could be something like :: AppHandler App App (Either String a) but you'll have to replace a with what you are parsing the JSON to. But then you'll have to define App type. I don't know if you can do AppHandler () () or not - DiegoNolan

1 Answers

1
votes

writeJSON has the type

writeJSON :: (MonadSnap m, ToJSON a) => a -> m ()

where the a and the m must be resolved to specific types before the compiler can run the code. You can certainly use your object of type [(String, Double)] as the input because String has an instance of ToJSON, as does Double, as do any pair of things with ToJSON instances (i.e. instance (ToJSON a, ToJSON b) => ToJSON (a, b)), and finally as do lists of things with ToJSON instances (i.e. instance ToJSON v => ToJSON [a]).

So the problem is entirely in trying to determine what m is. The compiler is complaining that as long as m is "anything" it cannot be sure that it's an instance of MonadSnap. We can reassure the type checker at least by just asserting it is so

>>> :t writeJSON [("foo", 3)] :: MonadSnap m => m ()
writeJSON [("foo", 3.0)] :: MonadSnap m => m ()

But we need to pick a concrete choice of m before we can run it. If you have a test application which uses MonadSnap then you can embed this line of code there, for instance.

For testing, however, you probably should just use the function that writeJSON depends upon: encode from Data.Aeson.

>>> encode [("foo", 3.0)]
"[[\"foo\",3.0]]"