Another possibility is to use monadic folds from Control.Lens.Action .
Monadic folds allow you to transfer your fold with effective actions so that these actions are interconnected with the process of โstudyingโ the data structure.
Note that this is different from mapMOf . Monadic folds allow you to do something like creating parts of the structure that are explored with the word "on the fly", for example, by loading them from disk or asking the user for input.
Ordinary folds are directly used as monadic folds. You just need to run them with specialized operators such as (^!!) and (^!?) .
To introduce an effect into a monadic fold, use the act function.
We can create a monadic fold working in the Writer monad and insert bend actions that "log". Something like that:
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE FlexibleContexts #-} import Control.Monad import Control.Monad.Writer import Control.Lens import Data.Monoid import Data.Aeson import Data.Aeson.Lens msg :: String -> IndexPreservingAction (Writer (Last String)) aa msg str = act $ \a -> tell (Last . Just $ str) >> return a main :: IO () main = do let str = "[{\"someObject\": {\"version\": [1, 0, 3]}}]" val = maybe (error "decode err") id . decode $ str :: Value monfol = nth 0 . msg "#1" . key "someObject" . msg "#2" . key "version" . msg "#3" . nth 2 (mresult,message) = runWriter $ val ^!? monfol putStrLn $ case mresult of Just result -> show result Nothing -> maybe "no messages" id . getLast $ message
If you change the "version" key in JSON to collapse the failure, the error message will be "# 2".
It would be nice to use some kind of error monad, like Either instead of Writer , to pinpoint the location of the failure, rather than the last "breakpoint". But I'm not sure if this is possible, because the fold already represents an error, returning Nothing .
The Control.Lens.Reified module has a ReifiedMonadicFold newtype that offers some useful instances for monadic folds. ReifiedMonadicFold behave a bit like the arrows of the Claysley monad, which is an instance of MonadPlus .