Reputation: 13
I'm trying to learn haskell, and what better a way than to learn by converting an already existing program I have made over to haskell, since I know how my program works otherwise.
the first step is to make a simple http get request to a link that provides me a JSON string. I have been digging, and dumpster diving through as much haskell documentation as I can, but I am getting the idea that haskell documentation is obviously... not accessible to non-haskell programmers.
I need to take a link- lets say https://aur.archlinux.org/rpc/?v=5&type=search&by=name-desc&arg=brave
and make a get request on that link. In other languages, there seemed to be an easy way to get the body of that response as a STRING. In haskell im wracking my brain with bytestrings? and "you cant do this because main is IO" and etc etc.
I just can't make any sense of it and I want to breach through this accessibility barrier that haskell has because I otherwise love functional programming, I dont wanna program another way!
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import qualified Data.ByteString.Char8 as B8
main :: IO ()
main = do
httpBS "https://aur.archlinux.org/rpc/?v=5&type=search&by=name-desc&arg=brave" >>= B8.putStrLn . getResponseBody
Doing this gets the response and outputs it as standard out, but I need to save this as a string, or convert it from a bytestring? to a string so that I can parse it.
If I sound defeated it's because I very much am.
Upvotes: 1
Views: 534
Reputation: 64740
what better a way than to learn by converting an already existing program I have made over to haskell, since I know how my program works otherwise.
This strategy will encourage you to carry over idioms from the original language. I'm guessing your prior language didn't encourage use of monads and wasn't lazy. Perhaps it wasn't even functional, but the point is this can actually be a detrimental start.
I just can't make any sense of it and I want to breach through this accessibility barrier
Learning to read documentation is hard in any unknown language (for me at least). Understanding each character is actually rather important. For example, a ByteString - an array of bytes, or just Bytes
if it were better named - isn't a hard concept but the name implies things to people.
If I sound defeated it's because I very much am.
You're so close! Think of the high level:
You did 1 already, nice work. Rather than do everything in a single line in point free style (composing a bunch of functions with a bunch of operators), let's name our intermediate values and have one concept per line:
#!/usr/bin/env cabal
{- cabal:
build-depends: base, http-conduit, aeson
-}
{-# LANGUAGE OverloadedStrings #-}
I'm using a shebang so I can just chmod +x file.hs
and ./file.hs
as I develop.
import Network.HTTP.Simple
import qualified Data.Aeson as Aeson
The most common JSON library in Haskell is Aeson, we'll use that to parse the bytes into json much like python's json.loads
.
main :: IO ()
main = do
httpRequest <- parseRequest "https://aur.archlinux.org/rpc/?v=5&type=search&by=name-desc&arg=brave"
response <- httpLBS httpRequest
You're start is good. Notice httpBS is a class of functions generically http<SomeTypeOfResult>
and not httpGet
like you might have seen in Java or Python. The function learns if this is a GET (vs POST etc) and the headers using fields in the Request
data type. To get a Request
we parse the URL string and just use all of parseRequest
s defaults (which is HTTP GET).
I did change to getting lazy byte strings (LBS) because I know the Aeson library uses those later on. This is something like an iterator that produces bytestrings (for intuition, not entirely accurate).
Rather than >>= moreFunctions
I'm naming the intermediate value response
so we can use it and look at each step separately.
let body = getResponseBody response
Extracting the body from the response is just like what you had, except as a separate expression.
let obj = Aeson.decode body :: Maybe Aeson.Object
The big part is to decode the bytes to JSON. This is hopefully familiar since every language under the sun does json decoding to some sort of dictionary/map/object. In Haskell you'll find it less common to decode to a map and more common to define a structure that is explicit in what you expect to have in the JSON then make a custom decoding routine for that type using the FromJSON class - you don't have to do that, it brings in way more concepts than you'll want when just getting started as a beginner.
print obj
I know this doesn't need explained.
Alternative
If you saw the documentation you might have seen (or considered searching the page for) JSON. This can save you lots of time!
#!/usr/bin/env cabal
{- cabal:
build-depends: base, http-conduit, aeson
-}
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import qualified Data.Aeson as Aeson
main :: IO ()
main = do
response <- httpJSON =<< parseRequest "https://aur.archlinux.org/rpc/?v=5&type=search&by=name-desc&arg=brave"
let obj = getResponseBody response :: Maybe Aeson.Object
print obj
Upvotes: 4