staeter / ziplist / ZipList

A ZipList is a list that has a single selected element. We call it current as "the one that is currently selected".

To get more explicit examples, I'm gonna represent ZipLists as Lists that have the selected element between "<...>":

Zipper [] 0 [1, 2, 3, 4]  == [<0>, 1, 2, 3, 4]
Zipper [2, 1, 0] 3 [4]    == [0, 1, 2, <3>, 4]

This pseudo-code will make the documentation way more enjoyable.

ZipLists


type ZipList a
    = Zipper (List a) a (List a)

A ZipList is a list that has a single selected element. We call it current as "the one that is currently selected".

type ZipList a
    = Zipper (List a) a (List a)

Create

new : a -> List a -> ZipList a

Craft a new ZipList out of a List and an element.

new "a" ["b", "c"] == [<"a">, "b", "c"]

fromList : List a -> Maybe (ZipList a)

Craft a new ZipList out of a List. Current is the first element of the List. Return Nothing if an empty list is given.

singleton : a -> ZipList a

Create a new ZipList with a single element in it.

current (singleton "my element") == "my element"

length (singleton "my element") == 1

Consult

current : ZipList a -> a

Return the current element of a ZipList.

toList : ZipList a -> List a

Convert a ZipList into a List.

toList ["a", <"b">, "c"] == ["a", "b", "c"]

length : ZipList a -> Basics.Int

Return a ZipList length.

length [0, 1, <2>, 3, 4]  == 5
length [<0>, 1, 2]        == 3

currentIndex : ZipList a -> Basics.Int

Return the index (starting at zero) of the current element.

currentIndex [0, 1, <2>, 3, 4]  == 2
currentIndex [<0>, 1, 2]        == 0

isCurrent : (a -> Basics.Bool) -> ZipList a -> Basics.Bool

Test wether current passes a condition.

isCurrent odd [4, <1>, 2]  == True
isCurrent odd [4, <6>, 2]  == False

isFirst : (a -> Basics.Bool) -> ZipList a -> Basics.Bool

Test wether the first element of the ZipList passes a condition.

isFirst odd [1, <4>, 2]  == True
isFirst odd [4, <4>, 2]  == False

isLast : (a -> Basics.Bool) -> ZipList a -> Basics.Bool

Test wether the last element of the ZipList passes a condition.

isLast odd [4, <2>, 3]  == True
isLast odd [4, <2>, 2]  == False

Edit

remove : ZipList a -> Maybe (ZipList a)

Remove current from a ZipList. The new current is in priority the ZipList's next element.

remove [0, 1, <2>, 3, 4] == Just [0, 1, <3>, 4]
remove [0, 1, <2>]       == Just [0, <1>]
remove [<"hello!">]      == Nothing

replace : a -> ZipList a -> ZipList a

Replace current from a ZipList with a new value.

replace 9 [0, 1, <2>, 3, 4] == [0, 1, <9>, 3, 4]
replace 9 [0, 1, <2>]       == [0, 1, <9>]

insert : a -> ZipList a -> ZipList a

Insert a new value in a ZipList. The current will be pushed backward to let the new value take its place.

insert 9 [0, 1, <2>, 3, 4] == [0, 1, 2, <9>, 3, 4]
insert 9 [0, 1, <2>]       == [0, 1, 2, <9>]

insertAfter : a -> ZipList a -> ZipList a

Insert a new value in a ZipList right after current.

insertAfter 9 [0, 1, <2>, 3, 4] == [0, 1, <2>, 9, 3, 4]
insertAfter 9 [0, 1, <2>]       == [0, 1, <2>, 9]

insertBefore : a -> ZipList a -> ZipList a

Insert a new value in a ZipList right before current.

insertBefore 9 [0, 1, <2>, 3, 4] == [0, 1, 9, <2>, 3, 4]

filter : (a -> Basics.Bool) -> ZipList a -> Maybe (ZipList a)

Keep elements that satisfy the test.

filter ((!=) 3) [0, 3, 3, 1, 3, <2>, 3, 4] == Just [0, 1, <2>, 4]
filter ((!=) 2) [0, 1, <2>, 3, 4] == Just [0, 1, <3>, 4]
filter ((!=) 4) [0, 1, 2, 3, <4>] == Just [0, 1, 2, <3>]
filter ((!=) 4) [4, <4>, 4, 4] == Nothing

reverse : ZipList a -> ZipList a

Reverse ZipList order.

filter [1, <2>, 3] == [3, <2>, 1]

removeAllPrevious : ZipList a -> ZipList a

.

removeAllPrevious [0, 1, <2>, 3, 4] == [<2>, 3, 4]

removeAllFollowing : ZipList a -> ZipList a

.

removeAllFollowing [1, <2>, 3, 4] == [1, <2>]

Move

forward : ZipList a -> ZipList a

Move current forward. Current will not move if it is at the end of the ZipList.

forward [0, 1, <2>, 3, 4] == [0, 1, 2, <3>, 4]
forward [0, 1, <2>]       == [0, 1, <2>]

backward : ZipList a -> ZipList a

Move current backward. Current will not move if it is at the beginning of the ZipList.

backward [0, 1, <2>, 3, 4] == [0, <1>, 2, 3, 4]
backward [<0>, 1, 2]       == [<0>, 1, 2]

jumpForward : Basics.Int -> ZipList a -> ZipList a

Move current forward a given amount of times. Current will be the last element of the ZipList if the jump size is too big.

jumpForward 2 [0, <1>, 2, 3, 4] == [0, 1, 2, <3>, 4]
jumpForward 2 [0, <1>, 2]       == [0, 1, <2>]

jumpBackward : Basics.Int -> ZipList a -> ZipList a

Move current backward a given amount of times. Current will be the first element of the ZipList if the jump size is too big.

jumpBackward 2 [0, 1, 2, <3>, 4] == [0, <1>, 2, 3, 4]
jumpBackward 2 [0, <1>, 2]       == [<0>, 1, 2]

maybeJumpForward : Basics.Int -> ZipList a -> Maybe (ZipList a)

Move current forward a given amount of times. Return Nothing if the jump size is too big.

maybeJumpForward 2 [0, <1>, 2, 3, 4] == Just [0, 1, 2, <3>, 4]
maybeJumpForward 2 [0, <1>, 2]       == Nothing

maybeJumpBackward : Basics.Int -> ZipList a -> Maybe (ZipList a)

Move current backward a given amount of times. Return Nothing if the jump size is too big.

maybeJumpBackward 2 [0, 1, 2, <3>, 4] == Just [0, <1>, 2, 3, 4]
maybeJumpBackward 2 [0, <1>, 2]       == Nothing

GoTo's

goToStart : ZipList a -> ZipList a

Move current to index 0.

goToStart [0, 1, 2, 3, <4>] == [<0>, 1, 2, 3, 4]
goToStart [<0>, 1, 2]       == [<0>, 1, 2]
goToStart [0, <1>, 2]       == [<0>, 1, 2]

goToEnd : ZipList a -> ZipList a

Move current to the end of the ZipList.

goToEnd [0, 1, 2, 3, <4>]   == [0, 1, 2, 3, <4>]
goToEnd [<0>, 1, 2]         == [0, 1, <2>]
goToEnd [0, <1>, 2]         == [0, 1, <2>]

goToIndex : Basics.Int -> ZipList a -> Maybe (ZipList a)

Move current to an index (starting at zero). Return Nothing if the index is too low and it will be the last element if the index is too high.

goToIndex 2 [0, 1, 2, 3, <4>] == Just [0, 1, <2>, 3, 4]
goToIndex 5 [0, <1>, 2]       == Nothing
goToIndex 1 [0, <1>, 2]       == Just [0, <1>, 2]

goToFirst : (a -> Basics.Bool) -> ZipList a -> Maybe (ZipList a)

Move current to the first element of a ZipList fulfilling a condition. Return Nothing if no matching element.

goToFirst isEven [8, 1, 2, 3, <4>] == Just [<8>, 1, 2, 3, 4]
goToFirst isEven [5, <1>, 2]       == Just [5, 1, <2>]
goToFirst isEven [1, <1>, 7]       == Nothing

goToNext : (a -> Basics.Bool) -> ZipList a -> Maybe (ZipList a)

Move current to the next element fulfilling a condition. Return Nothing if there is no matching element after current.

goToNext isEven [0, 1, <2>, 3, 4] == Just [0, 1, 2, 3, <4>]
goToNext isEven [8, 2, <1>, 3, 7] == Nothing
goToNext isEven [5, <1>, 2, 3]    == Just [5, 1, <2>, 3]

goToLast : (a -> Basics.Bool) -> ZipList a -> Maybe (ZipList a)

Move current to the last element of a ZipList fulfilling a condition. Return Nothing if there is no matching element.

goToLast isOdd [0, 1, <2>, 3, 4] == Just [0, 1, 2, <3>, 4]
goToLast isOdd [8, 2, <1>, 3, 7] == Just [8, 2, 1, 3, <7>]
goToLast isOdd [2, <4>, 6, 8]    == Nothing

goToPrevious : (a -> Basics.Bool) -> ZipList a -> Maybe (ZipList a)

Move current to the previous element fulfilling a condition. Return Nothing if there is no matching element before current.

goToPrevious isOdd [0, 1, <2>, 3, 4] == Just [0, <1>, 2, 3, 4]
goToPrevious isOdd [8, 2, 1, 4, <7>] == Just [8, 2, <1>, 4, 7]
goToPrevious isOdd [2, <4>, 3, 5]    == Nothing

Mapping

map : (a -> b) -> ZipList a -> ZipList b

Apply a function to every element of a ZipList.

map String.fromInt [0, 1, <2>, 3, 4] == ["0", "1", <"2">, "3", "4"]
map String.fromInt [2, <4>, 3, 5]    == ["2", <"4">, "3", "5"]

indexedMap : (Basics.Int -> a -> b) -> ZipList a -> ZipList b

Same as map but the function is also applied to the index of each element (starting at zero).

indexedMap Tuple.pair [1, <2>, 4]     == [(0, 1), <(1, 2)>, (2, 4)]
indexedMap Tuple.pair ["hi", <"wow">] == [(0, "hi"), <(1, "wow")>]

selectedMap : (Basics.Bool -> a -> b) -> ZipList a -> ZipList b

Same as map but the function also takes a boolean indicating wether it is current/the selected element.

selectedMap Tuple.pair [<2>, 4]             == [<(True, 2)>, (False, 4)]
selectedMap Tuple.pair ["en", "fr", <"ge">] == [(False, "en"), (False, "fr"), <(True, "ge")>]

indexedSelectedMap : (Basics.Int -> Basics.Bool -> a -> b) -> ZipList a -> ZipList b

Same as map but the function also takes the index of the element (starting at zero) and a boolean indicating wether it is current/the selected element.

let
  myFun =
    (\ index isCurrent elem ->
      (index, isCurrent, String.fromInt elem)
    )
in
  selectedMap myFun [1, <2>, 4] == [(0, False, "1"), <(1, True, "2")>, (2, False, "4")]

Encode / Decode

codec : Serialize.Codec e a -> Serialize.Codec e (ZipList a)

MartinSStewart/elm-serialize's codec serve as an encoder-decoder pair. It guarantees that your decoder return the input that was given to the encoder.