-1

This line of code should return a string but it returns IO(String).

simpleHTTP (getRequest "http://www.haskell.org/") >>= fmap (take 100) . getResponseBody

How can I pass the return value from the line above to getAllTextMatches?

import Network.HTTP
import Text.Regex.Posix

search :: String -> IO(String)
search url = do
 let link = (simpleHTTP (getRequest url) >>= fmap (take 50000). getResponseBody) 
 getAllTextMatches (link =~ "(<[a-zA-Z]+>)|(<[a-zA-Z][a-zA-Z]*\s)" :: AllTextMatches [] String)
user3105629
  • 53
  • 1
  • 2
  • 8
  • 1
    "Should" is a tricky word. I don't share your moral sensibilities: this line of code should return an `IO String`. But more to the point, what is your question? – Daniel Wagner Apr 14 '16 at 21:24
  • I am trying to get the body of the url. The body should start with ... I need to find all the tags in the body. How to get the return value from simpleHTTP (getRequest "http://www.haskell.org/") >>= fmap (take 100) . getResponseBody and pass it as an argument to getAllTextMatches so that it will return a list of string to me. – user3105629 Apr 14 '16 at 21:32
  • You can't (well, shouldn't... by my moral sensibilities) give that functionality a return type of `[String]`, but `IO [String]`. Happily the response below happens to answer your question if you modify it in this way. – Daniel Wagner Apr 15 '16 at 00:19
  • let f x = getAllTextMatches (x =~ "(<[a-zA-Z]+>)|(<[a-zA-Z][a-zA-Z]*\s)" :: AllTextMatches [] String) fmap f link -- IO [String] – gvd Apr 15 '16 at 05:44
  • Related: https://stackoverflow.com/q/7154518 . – atravers Sep 27 '21 at 03:58

2 Answers2

6

You need to use <- instead of let, = in the first line

let link = (simpleHTTP (getRequest url) >>= fmap (take 50000). getResponseBody) 

should be

link <- simpleHTTP (getRequest url) >>= fmap (take 50000). getResponseBody

This is because you are communicating with the outside world, and this all needs to happen in the IO monad.

Then link will be a String, and you can treat it as such.

At the end of the function you will want to return a type String also.


Update-

Here is an actual snippet that compiles for me:

search :: String -> IO [String]
search url = do
  link <- (simpleHTTP (getRequest url) >>= fmap (take 50000). getResponseBody) 
  return $ getAllTextMatches (link =~ "(<[a-zA-Z]+>)|(<[a-zA-Z][a-zA-Z]*\\s)" :: AllTextMatches [] String)

Note that getAllTextMatches returns an list of String, not a single String, so I had to change the type of search to String->IO [String]. If you want to preserve the type, you will have to change the code accordingly.

jamshidh
  • 12,002
  • 17
  • 31
0

In the Monad typeclass the >>= operator (pronounced bind) is defined as

(>>=) :: m a -> (a -> m b) -> m b

where m is some monad. In your example simpleHTTP (getRequest url) is the m a part of the definition and fmap (take 50000) . getResponseBody is the (a -> m b) part. >>= operates "inside" the IO monad as your question suggests, so the result of >>= is of type IO x (replace x with String in your example). To extract the underlying value from a monad inside a do block, use <-, like so:

link <- (simpleHTTP (getRequest url) >>= fmap (take 50000). getResponseBody) 
Kapol
  • 6,383
  • 3
  • 21
  • 46
  • When I pass link to the function getAllTextMatches, it gives me an error. I know that linke has a type IO[String]. How do I convert it to string? – user3105629 Apr 14 '16 at 21:41
  • @user3105629 I'm confused. Both answers state how to make `link` a string. Your problem lays elsewhere. Please update the question with the full compiler error message. – Kapol Apr 14 '16 at 21:48
  • Sorry for the wordings. The question I asked has two parts. The first part is asking how to get the return value from simpleHttp line. You all answered me. But the second part of the question I asked is asking how to pass the return value to getAllTextMatches. Thanks – user3105629 Apr 14 '16 at 21:58