Skip to content

Instantly share code, notes, and snippets.

@JordanMartinez
Last active October 25, 2018 02:17
Show Gist options
  • Save JordanMartinez/9e558dff223ebc6c40943b3fa4655b78 to your computer and use it in GitHub Desktop.
Save JordanMartinez/9e558dff223ebc6c40943b3fa4655b78 to your computer and use it in GitHub Desktop.
Undo Manager: Zipperless / One-Hole Context version vs Zipper version
-- Zipperless / One-Hole Context
import Data.List (List(..), null, (:))
import Data.Tuple (Tuple(..))
class Invertable change where
invert :: change -> change
class Undoable a change where
applyChange :: a -> change -> a
type Zipperless a =
{ undos :: List a
, redos :: List a
}
hasUndo :: forall a. Zipperless a -> Boolean
hasUndo z = null z.undos
hasRedo :: forall a. Zipperless a -> Boolean
hasRedo z = null z.redos
undo :: forall a change. Invertable change => Undoable a => ZipperLess change -> a -> Tuple a (ZipperLess change)
undo obj self@{ undos: Nil, redos: _ } = Tuple obj self
undo obj self@{ undos: (head : tail), redos: r } =
let result = applyChange obj head
inverted = invert head
in Tuple result { undos: tail, redos: (inverted : r) }
redo :: forall a change. Invertable change => Undoable a => ZipperLess change -> a -> Tuple a (ZipperLess change)
redo obj self@{ undos: _, redos: Nil } = Tuple obj self
redo obj self@{ undos: u, redos: (head : tail) } =
let result = applyChange obj head
inverted = invert head
in Tuple result { undos: (inverted : tail), redos: tail }
-- Using a Zipper
import Data.List (List(..), null, (:))
class Invertable change where
invert :: change -> change
class Undoable a change where
applyChange :: a -> change -> a
type UndoManager a b =
{ undos :: List b
, focus :: a
, redos :: List b
}
hasUndo :: forall a b. UndoManager a b -> Boolean
hasUndo z = null z.undos
hasRedo :: forall a b. UndoManager a b -> Boolean
hasRedo z = null z.redos
undo :: forall a b. Invertable b => Undoable a => UndoManager a b -> UndoManager a b
undo self@{ undos: Nil, focus: _, redos: _ } = self
undo { undos: (head : tail), focus: focus, redos: r } =
let result = applyChange focus head
inverted = invert head
in { undos: tail, focus = result, redos: (inverted : r) }
redo :: forall a b. Invertable b => Undoable a => UndoManager a b -> UndoManager a b
redo self@{ undos: _, focus: _, redos: Nil } = self
redo { undos: u, focus: focus, redos: (head : tail) } =
let result = applyChange focus head
inverted = invert head
in { undos: (inverted : u), focus = result, redos: tail }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment