2

I want to add a custom field to my posts called coolness, like this:

---
title: Something
coolness: 10
---

and then I want to sort my posts by coolness. How do I do that? I know I can sort by date: posts <- recentFirst =<< loadAll "posts/*" using recentFirst, but that's built-in and I don't really know how to modify it to sort by coolness instead because it uses some custom method to find out what date a post has.

user3760874
  • 75
  • 1
  • 5

1 Answers1

1

We want to use MonadMetadata and getMetadataField from Hakyll to read the coolness, then parse it to a number, and sort by that number.

Stealing heavily from The source for recentFirst, you could write something like:

{-# LANGUAGE TupleSections #-}
import Hakyll
import Control.Monad (void, (>>=), liftM)
import Data.Ord (comparing)
import Data.List(sortOn, sortBy)
import Data.Maybe(fromMaybe)
import Text.Read(readMaybe)
import Data.Foldable (toList)

-- this parses the coolness out of an item
-- it defaults to 0 if it's missing, or can't be parsed as an Int
coolness :: MonadMetadata m => Item a -> m Int
coolness i = do 
    mStr <- getMetadataField (itemIdentifier i) "coolness"
    return $ (fromMaybe 0 $ mStr >>= readMaybe)

byCoolness :: MonadMetadata m => [Item a] -> m [Item a]
byCoolness = sortByM coolness
  where
    sortByM :: (Monad m, Ord k) => (a -> m k) -> [a] -> m [a]
    sortByM f xs = liftM (map fst . sortBy (comparing snd)) $
                   mapM (\x -> liftM (x,) (f x)) xs

This sorts on the extracted coolness value. It sorts in increasing coolness, so if you want "coolest first" do:

posts <- reverse <$> (byCoolness =<< loadAll "posts/*")
Joe
  • 1,479
  • 13
  • 22
  • there are a bunch of equivalent alternatives to that `sortByM` implementation, such as the (slightly different) [`sortByM` from the monadlist package](http://hackage.haskell.org/package/monadlist-0.0.2/docs/Control-Monad-ListM.html) – Joe Jul 03 '20 at 14:07