Add Box instances to allow handling some exceptions in monad and converting them to Traversable accessible from the data part of the type

This commit is contained in:
Tissevert 2020-02-27 17:22:12 +01:00
parent 99014ff30d
commit d90eaf6f1c

View file

@ -3,21 +3,27 @@
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
module PDF.Box ( module PDF.Box (
Box(..) Box(..)
, I(..) , Index(..)
, Maybe_(..)
, Either_(..)
, at , at
, atAll , atAll
, edit , edit
) where ) where
import Control.Monad.Except (ExceptT(..), runExceptT)
import Control.Monad.Fail (MonadFail(..)) import Control.Monad.Fail (MonadFail(..))
import Control.Monad.State (MonadState(..)) import Control.Monad.State (MonadState(..))
import Data.Map (Map) import Data.Map (Map)
import qualified Data.Map as Map (insert, lookup, member) import qualified Data.Map as Map (insert, lookup, member)
import Prelude hiding (fail) import Prelude hiding (fail)
newtype I = I Int newtype Index = Index Int
newtype Maybe_ x = Maybe_ x
newtype Either_ b x = Either_ x
class Monad m => Box m i a b | m a i -> b where class Monad m => Box m i a b | m a i -> b where
r :: i -> a -> m b r :: i -> a -> m b
@ -32,17 +38,14 @@ atAll i f = at i $ (mapM f)
edit :: MonadState a m => (a -> m a) -> m () edit :: MonadState a m => (a -> m a) -> m ()
edit f = get >>= f >>= put edit f = get >>= f >>= put
instance MonadFail m => Box m I [a] a where instance MonadFail m => Box m Index [a] a where
r (I i) = getAt i r (Index i) [] = fail $ "Index out of bounds " ++ show i
where r (Index 0) (x:_) = return x
getAt _ [] = fail $ "Index out of bounds " ++ show i r (Index i) (_:xs) = r (Index (i-1)) xs
getAt 0 (x:_) = return x
getAt k (_:xs) = getAt (k+1) xs w (Index i) _ [] = fail $ "Index out of bounds " ++ show i
w (I i) newX = setAt i w (Index 0) newX (_:xs) = return (newX:xs)
where w (Index i) newX (x:xs) = (x:) <$> w (Index (i-1)) newX xs
setAt _ [] = fail $ "Index out of bounds " ++ show i
setAt 0 (_:xs) = return (newX:xs)
setAt k (x:xs) = (x:)<$>(setAt (k-1) xs)
instance (Ord k, MonadFail m) => Box m k (Map k a) a where instance (Ord k, MonadFail m) => Box m k (Map k a) a where
r k = maybe (fail "Unknown key") return . Map.lookup k r k = maybe (fail "Unknown key") return . Map.lookup k
@ -50,3 +53,15 @@ instance (Ord k, MonadFail m) => Box m k (Map k a) a where
| Map.member k aMap = | Map.member k aMap =
return $ Map.insert k a aMap return $ Map.insert k a aMap
| otherwise = fail "Unknown key" | otherwise = fail "Unknown key"
instance (Monad m, Box Maybe i a b) => Box m (Maybe_ i) a (Maybe b) where
r (Maybe_ i) = return . r i
w (Maybe_ i) (Just b) a =
return . maybe a id $ w i b a
w _ _ obj = return obj
instance (Monad m, Box (ExceptT e m) i a b) => Box m (Either_ e i) a (Either e b) where
r (Either_ i) a = runExceptT (r i a)
w (Either_ i) (Right b) a =
either (const a) id <$> runExceptT (w i b a :: ExceptT e m a)
w _ _ a = return a