hakyll icon indicating copy to clipboard operation
hakyll copied to clipboard

Add boolFieldM which allows using the Compiler monad

Open Kritzefitz opened this issue 7 years ago • 6 comments

This commits adds the helper boolFieldM. In contrast to boolField it allows using the Compiler monad in the passed function. boolField is also redefined in terms of boolFieldM. Closes #564

Kritzefitz avatar Sep 02 '17 14:09 Kritzefitz

Any news on this PR?

bdesham avatar Nov 14 '17 06:11 bdesham

Just curious, what are you using this for? Also what would you think of a maybeField :: String -> (Item a -> Compiler (Maybe String)) -> Context a

bergus avatar Mar 11 '18 21:03 bergus

Just curious, what are you using this for?

I'm building a multi-level navigation menu by iterating over Items. Links in the navigation that link to the current site or to sites hierarchically above the current site should be rendered in a special way. I currently do this by giving each of the menu Items a field that tests for the conditions mentioned above by comparing parts of the Item's Identifier with the current page's Identifier. The latter is obtained with getUnderlying, which is what I need the Compiler for.

Also what would you think of a maybeField :: String -> (Item a -> Compiler (Maybe String)) -> Context a

Definitely looks like something that might be useful from time to time.

Kritzefitz avatar Mar 11 '18 22:03 Kritzefitz

I'm fine merging this unless this conflicts with the progress on better error messages @bergus

jaspervdj avatar Mar 12 '18 15:03 jaspervdj

No, doesn't really conflict with that (the collision is easy to resolve), however I'm not sold on the name boolFieldM. We should get a clear naming convention for how to construct Contexts with functions that return strings, bools, lists (or Compilers for them) from items, from items+arguments or from nothing.

Also I'm currently experimenting with

class ContextFieldable a where -- a horrible name. Suggestions?
    toContextField :: a -> Compiler ContextField

instance ContextFieldable ContextField where
    toContextField = return

instance ContextFieldable a => ContextFieldable (Compiler a) where
    toContextField = (>>= toContextField)

instance ContextFieldable [Char] where
    toContextField = return . StringField

instance ContextFieldable Bool where
    toContextField True  = return EmptyField
    toContextField False = compilerNoResult "false"

instance ContextFieldable a => ContextFieldable (Maybe a) where
    toContextField = maybe (compilerNoResult "false") toContextField

--------------------------------------------------------------------------------
functionContext :: ContextFieldable c => String -> ([String] -> Item a -> c) -> Context a
functionContext key value = Context $ \k args item ->
    if k == key
        then mapError (("In field "++key):) $ toContextField $ value args item
        else compilerNoResult $ "Tried field " ++ key

context :: ContextFieldable c => String -> (Item a -> c) -> Context a
context key = functionContext key . const

which would allow field = context, boolField = context, constField key = context key . const, functionField = functionContext, and also boolFieldM = context - it's super-flexible. Maybe too flexible? If you want to consider this, I'm gonna file a separate pull request, superseding this one. Either is largely independent from the error messages PR though.

bergus avatar Mar 12 '18 15:03 bergus

Oh yeah something like that would work as well. I would just call the typeclass ToContextField.

jaspervdj avatar Mar 12 '18 15:03 jaspervdj