I declared a group on applicative functors. Judging by what we usually call "actions", it seems that such group would enable the action to be undone:
import Control.Applicative
class Alternative f => Undoable f where
undo :: f a -> f a
Being a group, for all x :: Undoable f => f a
, the following laws shall satisfy:
x <|> undo x ≡ empty
undo x <|> x ≡ empty
Some instances:
import Control.Arrow
import Data.Functor.Compose
import Data.Functor.Product
import Data.Proxy
instance Undoable Proxy where
undo _ = Proxy
instance (Undoable f, Applicative g) => Undoable (Compose f g) where
undo (Compose x) = Compose (undo x)
instance (Undoable f, Undoable g) => Undoable (Product f g) where
undo (Pair x y) = Pair (undo x) (undo y)
instance Undoable m => Undoable (Kleisli m a) where
undo (Kleisli f) = Kleisli (undo . f)
At least for me, these instances are of no interest. Some non-instances include:
Maybe
: Once successful, it will be always a success regardless of other options.[]
andZipList
: Options always add nondeterminism, not subtract from it.ReadP
andReadPrec
: As implied by above.
IO
: Taken literally, this instance would be a time machine. Even though we may take the quotient of the reality over time-space, there is a practical counterexample: A newIORef
cannot be forgotten.
Is there any particularly interesting instance of Undoable
?
I would consider something like this. Not a
Prelude.Functor
because the keys need to be orderable (could also beHashable
or onlyEq
, you know the tradeoffs).It's basically a multiset that allows negative multiplicities. Antimatter elements as it were.
with
I think there can be a conforming
Applicative
/Alternative
built around this, but I'm not completely sure.