haskellhakyll

How to fit in IO type when using external libraries


I'm trying out Hakyll and having trouble fitting in IO type into Hakyll compilation process. Here's an example Hakyll code from tutorial.

main :: IO ()
main = hakyll $ do
    match "posts/*" $ do
        route $ setExtension "html"
        compile $ do
            let url = -- $1
                ctx = stringField "title" url `mappend` defaultCtx
                in
                pandocCompiler
                >>= loadAndApplyTemplate "templates/default.html" ctx
                >>= relativizeUrls

I want to look at the list of localized files (en.md, fr.md, ...) in matched directories and produce a list of available languages, which I will use to generate urls for redirecting to translations. I think this logic will have to be placed around $1.

It's file operation so it produces IO [FilePath]. But $1 is inside Hakyll.Compiler monad, which is computed inside Hakyll.Rules and IO monads. Somehow I need to deal with IO type to work within the type signatures set by the library author. What is a good way to do this?

There are a few other implementations I can think of that avoid accessing file system and producing IO type, but I want to do it this way if possible. Plus, I want to get down to the bottom of this as it looks like a kind of issue that I may face commonly while writing Haskell.


Solution

  • It might not be necessary to use IO, and that should generally be avoided because it prevents Hakyll from tracking dependencies.

    There is a loadAll function to get all items matching a pattern (in your case, possibly "posts/currentpost/*.md", that might need messing with getResourceFilePath to construct). Then given all those Item you can look at their itemIdentifier and extract the basenames/languages (fr, en...).

    -- rough sketch
    
    ...
      compile $ do
        currentPath <- getResourceFilePath
        allItems <- loadAll ... :: Compiler [Item ()]  -- () ignores the contents
        let idens = map itemIdentifier allItems
            url = ... idens
        ...