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.
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
...