hakyll icon indicating copy to clipboard operation
hakyll copied to clipboard

Possible type consistencies between loadAll and Contexts should be detected by the type system

Open damiencourousse opened this issue 5 years ago • 1 comments

Suppose I use the following (buggy) code snippet.

    match "images/*" $ do
      route idRoute
      compile copyFileCompiler

    create ["images.html"] $ do
      route idRoute
      compile $ do
        photos <- loadAll "images/*"
        let imageCtx :: Context String
            imageCtx = urlField "url"
                       <> pathField "path"
                       <> missingField
            photosCtx :: Context String
            photosCtx = constField "title" "images"
                        <> listField "photos" imageCtx (loadAll "images/*")
                        <> missingField
                        <> defaultContext

This code will happily compile but will produce an error at runtime, such as:

  [ERROR] Hakyll.Core.Compiler.Require.load: images/IMG_6139.JPG (snapshot _final) was found in the cache, but does not have the right type: expected [Char] but got CopyFile

The fix consists in declaring imageCtx as Context CopyFile. The reason seems to be that loadAll can only items that have already been compiled by a match rule (e.g. here). My understanding is that in the buggy example above, the images have been compiled by copyFileCompiler of type Compile (Item CopyFile). Hence loadAll "images/*" need to be typed as Compiler [Item CopyFile], and imageCtx is Context CopyFile.

This subtlety is not explicited by the type properties of Hakyll, nor by the documentation. I don't know what can be done to help hakyll users, but I wanted to share this because it took me a lot of time to understand what was happening here.

And.... thanks for this great library!!

damiencourousse avatar Jul 30 '19 13:07 damiencourousse

That's a good point to add to the docs #904. In the beginning i tripped over that as well.

malteneuss avatar Nov 18 '21 12:11 malteneuss