2

Everything was working great up until about a month or so ago...

Suddenly I'm getting

 berkson.github.io/source/blog.hs: 333, 42
 • Couldn't match type ‘unordered-containers-0.2.7.1:Data.HashMap.Base.HashMap
                          text-1.2.2.1:Data.Text.Internal.Text
                          aeson-0.11.2.0:Data.Aeson.Types.Internal.Value’
                  with ‘M.Map [Char] [Char]’
   Expected type: M.Map [Char] [Char]
     Actual type: Metadata
 • In the first argument of ‘(M.!)’, namely ‘md’
   In the first argument of ‘(++)’, namely ‘(md M.! "author")’
   In the second argument of ‘(++)’, namely ‘(md M.! "author") ++ "/"’

From the code:

 directorizeDateAndAuthor :: Routes
 directorizeDateAndAuthor = metadataRoute $ \md ->
     gsubRoute "/[0-9]{4}-[0-9]{2}-[0-9]{2}-" $ \s ->
         replaceAll "-" (const "/") s ++ (md M.! "author") ++ "/"

I was wondering if you'd mind helping me decipher what exactly it's telling me? I get that there's some type of syntax error on my end, but I don't understand what changed and why it's not compiling like it used to?

Ref: https://github.com/berkson/berkson.github.io/blob/source/source/blog.hs#L330

Berkson
  • 65
  • 4
  • 3
    My guess is that you upgraded the package that defines `Metadata`, and that package changed from defining it to be in terms of `Map` to `HashMap`. You need to update your usages of this type to use e.g. `HashMap.!` instead of `M.!`. Or you could just change your cabal file to depend on an older version of the package. – luqui Jun 14 '16 at 01:13
  • 2
    In hakyll 4.8 `Metadata` type changed from `Map` to `Aeson.Object` (see [release announcement](https://groups.google.com/forum/#!topic/hakyll/M3SNUkH2zsQ)) – Jan Tojnar Jun 14 '16 at 10:53
  • @JanTojnar gah! Thank you for telling me, but now I'm even more lost! I thought it'd be just a drop in replacement for itself but instead of the error before I'm getting: `Couldn't match expected type ‘[Char]’ with actual type ‘Value’` Instead! >_< Haskell is so confusing to me still. – Berkson Jun 15 '16 at 00:28

1 Answers1

4

Before hakyll 4.8 the Metadata type synonym was defined as follows:

type Metadata = HashMap.Map String String

The metadata were just a flat list of key – value pairs.

In hakyll 4.8, metadata parsing was changed (issue, commit, release anouncement) to use YAML parser, to allow more complex metadata structure. Now, the type synonym is following:

type Metadata = Aeson.Object

This is the Object from aeson package – Data.Yaml library shares the types.

Unfortunately, handling the Aeson.Object is not as straightforward as the Map was. To learn how to use Aeson properly, you can read a lengthy tutorial.

Luckily, Jasper provided us with a function lookupString which is almost a drop-in replacement of HashMap.!:

(!) :: Metadata -> String -> String
lookupString :: String -> Metadata -> Maybe String

Unwrapping the Maybe value, you will then get something like the following code:

directorizeDateAndAuthor :: Routes
directorizeDateAndAuthor = metadataRoute $ \md ->
  case lookupString "author" md of
      Just author ->
          gsubRoute "/[0-9]{4}-[0-9]{2}-[0-9]{2}-" $ \s ->
              replaceAll "-" (const "/") s ++ author ++ "/"
      Nothing -> error "The author metadata field is missing."
Jan Tojnar
  • 5,306
  • 3
  • 29
  • 49