-- |
-- Module      :  Cryptol.Utils.Misc
-- Copyright   :  (c) 2014-2016 Galois, Inc.
-- License     :  BSD3
-- Maintainer  :  cryptol@galois.com
-- Stability   :  provisional
-- Portability :  portable

{-# LANGUAGE Safe, FlexibleContexts #-}
module Cryptol.Utils.Misc where

import MonadLib

import Prelude ()
import Prelude.Compat

-- | Apply a function to all elements of a container.
-- Returns `Nothing` if nothing changed, and @Just container@ otherwise.
anyJust :: Traversable t => (a -> Maybe a) -> t a -> Maybe (t a)
anyJust :: (a -> Maybe a) -> t a -> Maybe (t a)
anyJust a -> Maybe a
f t a
m = (t a, Bool) -> Maybe (t a)
forall a. (a, Bool) -> Maybe a
mk ((t a, Bool) -> Maybe (t a)) -> (t a, Bool) -> Maybe (t a)
forall a b. (a -> b) -> a -> b
$ Lift (t a, Bool) -> (t a, Bool)
forall a. Lift a -> a
runLift (Lift (t a, Bool) -> (t a, Bool))
-> Lift (t a, Bool) -> (t a, Bool)
forall a b. (a -> b) -> a -> b
$ Bool -> StateT Bool Lift (t a) -> Lift (t a, Bool)
forall i (m :: * -> *) a. i -> StateT i m a -> m (a, i)
runStateT Bool
False (StateT Bool Lift (t a) -> Lift (t a, Bool))
-> StateT Bool Lift (t a) -> Lift (t a, Bool)
forall a b. (a -> b) -> a -> b
$ (a -> StateT Bool Lift a) -> t a -> StateT Bool Lift (t a)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse a -> StateT Bool Lift a
forall (m :: * -> *). StateM m Bool => a -> m a
upd t a
m
  where
  mk :: (a, Bool) -> Maybe a
mk (a
a,Bool
changes) = if Bool
changes then a -> Maybe a
forall a. a -> Maybe a
Just a
a else Maybe a
forall a. Maybe a
Nothing

  upd :: a -> m a
upd a
x = case a -> Maybe a
f a
x of
            Just a
y  -> Bool -> m ()
forall (m :: * -> *) i. StateM m i => i -> m ()
set Bool
True m () -> m a -> m a
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
y
            Maybe a
Nothing -> a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x

-- | Apply functions to both elements of a pair.
-- Returns `Nothing` if neither changed, and @Just pair@ otherwise.
anyJust2 :: (a -> Maybe a) -> (b -> Maybe b) -> (a,b) -> Maybe (a,b)
anyJust2 :: (a -> Maybe a) -> (b -> Maybe b) -> (a, b) -> Maybe (a, b)
anyJust2 a -> Maybe a
f b -> Maybe b
g (a
a,b
b) =
  case (a -> Maybe a
f a
a, b -> Maybe b
g b
b) of
    (Maybe a
Nothing, Maybe b
Nothing) -> Maybe (a, b)
forall a. Maybe a
Nothing
    (Just a
x , Maybe b
Nothing) -> (a, b) -> Maybe (a, b)
forall a. a -> Maybe a
Just (a
x, b
b)
    (Maybe a
Nothing, Just b
y ) -> (a, b) -> Maybe (a, b)
forall a. a -> Maybe a
Just (a
a, b
y)
    (Just a
x , Just b
y ) -> (a, b) -> Maybe (a, b)
forall a. a -> Maybe a
Just (a
x, b
y)