Search code examples
haskellfunctional-programmingmonadscompositionfunctor

How can you add a String to a list of Monads in Haskell


I am a new to functional programming. I am scraping a website using Scalpel and I need to extract information from links contained in that website. What I can extrapolate though is just part of the link and I need to add to the String "http://www.google.com/" to each of these links. I can't do a normal ++ because I don't have a list of Strings.

Here's the code:

{-# LANGUAGE OverloadedStrings #-}

import Text.HTML.Scalpel

main :: IO ()
main = do
  res <- scrapeURL "http://www.whateverLink/" scrapeComic
  print res

scrapeComic :: Scraper String [[String]]
scrapeComic =
  chroots ("ul" @: ["id" @= "research-teachinglist"]) scrapeLink

scrapeLink :: Scraper String [String]
-- This returns me the parts of the links I want 
scrapeLink = (attrs "href" "a")

-- I tried this, but it doesn't work
-- scrapeLink = mapM_ ("http://www.google.com/" ++) (attrs "href" "a")

Any ideas?

Thank you


Solution

  • You have

    attrs "href" "a" :: Scraper String [String]
    

    and

    ("http://www.google.com/" ++) :: String -> String
    

    and you'd like to apply the latter to all the String elements in the former's result list.

    First of all, applying it to lists is a matter of

    map :: (a -> b) -> [a] -> [b]
    

    so in your case, you have

    map ("http://www.google.com/" ++) :: [String] -> [String]
    

    Which gets us one step closer.

    Now the next problem is that instead of a pure [String] value, you have a computation Scraper String [String]. However, Scraper str is an instance of Functor for any choice of str, in particular, for str ~ String, i.e. Scraper String is a Functor.

    What that gives us is a way of applying pure functions to Scraper Strings:

    fmap :: (a -> b) -> Scraper String a -> Scraper b
    

    in particular, we have

    fmap (map ("http://www.google.com/" ++)) :: Scraper String [String]
    

    leading to

    scrapeLink :: Scraper String [String]
    scrapeLink = fmap (map ("http://www.google.com/" ++)) (attrs "href" "a")