UndoList Data Structure.
{ past : List state
, present : state
, future : List state
}
The UndoList data structure. An UndoList has:
The head of the past list is the most recent state and the head of the future list is the next state. (i.e., the tails of both lists point away from the present)
undo : UndoList state -> UndoList state
If the undolist has any past states, set the most recent past state as the current state and turn the old present state into a future state.
i.e.
undo (UndoList [ 3, 2, 1 ] 4 [ 5, 6 ]) --> UndoList [ 2, 1 ] 3 [ 4, 5, 6 ]
redo : UndoList state -> UndoList state
If the undo-list has any future states, set the next future state as the current state and turn the old present state into a past state.
i.e.
redo (UndoList [ 3, 2, 1 ] 4 [ 5, 6 ]) --> UndoList [ 4, 3, 2, 1 ] 5 [ 6 ]
fresh : state -> UndoList state
Turn a state into an undo-list with neither past nor future.
new : state -> UndoList state -> UndoList state
Add a new present state to the undo-list, turning the old present state into a past state and erasing the future.
forget : UndoList state -> UndoList state
Forget the past and look to the future! This simply clears the past list.
i.e.
forget (UndoList [3,2,1] 4 [5,6]) --> UndoList [] 4 [5,6]
reset : UndoList state -> UndoList state
Reset the undo-list by returning to the very first state and clearing all other states.
i.e.
reset (UndoList [ 3, 2, 1 ] 4 [ 5, 6 ]) --> UndoList [] 1 []
hasPast : UndoList state -> Basics.Bool
Check if the undo-list has any past states.
hasPast (UndoList [] 1 []) --> False
hasPast (UndoList [ 1, 2, 3 ] 4 []) --> True
hasFuture : UndoList state -> Basics.Bool
Check if the undo-list has any future states.
hasFuture (UndoList [] 1 []) --> False
hasFuture (UndoList [] 1 [ 2, 3, 4 ]) --> True
length : UndoList state -> Basics.Int
Get the full length of an undo-list
length (UndoList [ 0 ] 1 [ 2, 3, 4 ]) --> 5
lengthPast : UndoList state -> Basics.Int
Get the length of the past.
lengthPast (UndoList [ 0 ] 1 [ 2, 3, 4 ]) --> 1
lengthFuture : UndoList state -> Basics.Int
Get the length of the future
lengthFuture (UndoList [ 0 ] 1 [ 2, 3, 4 ]) --> 3
Simple UndoList Msg type. This is a simple type that can be used for
most use cases. This works best when paired with the update
function as
update
will perform the corresponding operations on the undolist automatically.
Consider using your own data type only if you really need it.
mapMsg : (a -> b) -> Msg a -> Msg b
Map a function over a msg.
mapMsg sqrt (New 100) --> New 10
mapMsg sqrt Undo --> Undo
map : (a -> b) -> UndoList a -> UndoList b
Map a function over an undo-list.
Be careful with this. The function will be applied to the past and the future
as well. If you just want to change the present, use mapPresent
.
A good use case for map
is to encode an undo-list as JSON.
Example:
import UndoList.Encode as Encode
encode encoder undolist =
map encoder undolist
|> Encode.undolist
mapPresent : (a -> a) -> UndoList a -> UndoList a
Apply a function only to the present.
update : (msg -> state -> state) -> Msg msg -> UndoList state -> UndoList state
Convert a function that updates the state to a function that updates an undo-list. This is very useful to allow you to write update functions that only deal with the individual states of your system and treat undo/redo as an add on.
Example:
-- Your update function
update msg state =
case msg of
... -- some implementation
-- Your new update function
updateWithUndo = UndoList.update update
connect : UndoList state -> UndoList state -> UndoList state
Connect two undo-lists end to end. The present of the first undolist is considered the present of the output undolist.
reduce : (a -> b -> b) -> b -> UndoList a -> b
Alias for foldl
foldl : (a -> b -> b) -> b -> UndoList a -> b
Reduce an undo-list from the left (or from the past)
foldr : (a -> b -> b) -> b -> UndoList a -> b
Reduce an undo-list from the right (or from the future)
reverse : UndoList a -> UndoList a
Reverse an undo-list.
flatten : UndoList (UndoList a) -> UndoList a
Flatten an undo-list of undo-lists into a single undo-list.
flatMap : (a -> UndoList b) -> UndoList a -> UndoList b
Map over an undo-list and then flatten the result.
andThen : (a -> UndoList b) -> UndoList a -> UndoList b
Chain undo-list operations. This is simply an alias of flatMap
map2 : (a -> b -> c) -> UndoList a -> UndoList b -> UndoList c
Map a function over a pair of undo-lists.
andMap : UndoList a -> UndoList (a -> b) -> UndoList b
Map a function over any number of undo-lists.
map f xs
|> andMap ys
|> andMap zs
view : (state -> view) -> UndoList state -> view
Function to help not having to deal with the full undolist from with your actual view function.
Suppose you define the following:
initial : model
update : msg -> model -> model
view : model -> Html (UndoList.Msg msg)
Then, you could construct the main function as follows:
main =
Html.beginnerProgram
{ model = UndoList.fresh initial
, update = UndoList.update update
, view = UndoList.view view
}
toList : UndoList state -> List state
Convert an undo-list to a list :
toList (UndoList [ 3, 2, 1 ] 4 [ 5, 6 ]) --> [ 1, 2, 3, 4, 5, 6 ]
fromList : state -> List state -> UndoList state
Convert a list to undolist. The provided state is used as the present state and the list is used as the future states.
fromList 1 [ 2, 3, 4 ] --> UndoList [] 1 [ 2, 3, 4 ]