0

I am new to Haskell. I need to read the contents from a directory (i.e list all the files in the directory) and convert it to HTML. I have a codebase which uses the Yesod framework.

Now, I was able to read the directory contents using getDirectoryContents which returns type of IO [FilePath]. I want to be able to represent this in HTML.

Can someone help me on this? So far this is what I have tried. The error that I get is: Couldn't match type ‘IO’ with ‘Text.Blaze.Internal.MarkupM’ Expected type: Text.Blaze.Internal.MarkupM Html Actual type: IO Html

Please check the code below:

{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}

import Yesod.Core
import Text.Blaze.Html (toValue, (!))
import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as HA
import System.Directory as FS



getTestHamletR = defaultLayout $ do
    setTitle "Test Hamlet"
    toWidget $ \render -> do
           H.p $ do
                result <- fmap toHtml $ getListOfFiles "/home/chetan"
                result

Here is the getListOfFiles function:

getListOfFiles::FilePath -> IO [FilePath]
getListOfFiles fpath = FS.getDirectoryContents fpath
Chetan Yewale
  • 192
  • 4
  • 16
  • Probable duplicate of http://stackoverflow.com/questions/1675366/a-haskell-function-of-type-io-string-string – jkeuhlen Jan 12 '17 at 14:32
  • 2
    Possible duplicate of [A Haskell function of type: IO String-> String](http://stackoverflow.com/questions/1675366/a-haskell-function-of-type-io-string-string) – jkeuhlen Jan 12 '17 at 14:32
  • The error you see is because `fmap toHtml $ getListOfFiles "/home/chetan"` has type `IO (MarkupM ())`, since `type Html = MarkupM ()` in the blaze-html library. However, the `H.p` function has type `Html -> Html`, so it takes a `MarkupM ()` and returns a new `MarkupM ()`. You're giving it a `IO (MarkupM ())`, so the compiler complains. You'll have to do the `getListOfFiles` outside of your blaze code. – bheklilr Jan 12 '17 at 14:45

1 Answers1

3

I'm not well versed in Yesod, but this should work.

You cannot convert an IO value to non-IO value. However, you can work with these values, while staying in IO. To say it somewhat incorrectly, you can work with these values while being inside IO. I.e. this should work (not-tested):

getTestHamletR = do
    files <- liftIO $ getListOfFiles "/home/chtan"
    defaultLayout $ do
        setTitle "Test Hamlet"
        toWidget $ \render -> do
           H.p $ toHtml (intercalate ", " files)

I guess that getTestHamletR is not directly IO, but it is some layer above IO, so we can use liftIO to convert the IO [FilePath] to m [FilePath] where m is the Monad yesod uses.

The getTestHamletR is an IO function - every line works inside IO, you get the directory contents as IO [FilePath] and you essentially convert it to IO Html.

ondra
  • 9,122
  • 1
  • 25
  • 34
  • Thanks. H.p does not work on [Html]. It works on Html only. I am getting the related error which mentions it. Any idea how I could fix it – Chetan Yewale Jan 12 '17 at 14:52
  • That depends on you - you have a list of files and want to convert it to html. The function `toHtml` converts e.g. a `String` to html, so e.g. in this example I have concatenated the strings together. Import the `interacalate` from `Data.List`. – ondra Jan 12 '17 at 14:58