A list zipper that can also focus on a hole between items.
A HoleyFocusList Item a is focussed on an element of type a.
🍍 🍓 <🍊> 🍉 🍇An empty HoleyFocusList focussed on a hole with nothing before
and after it.
It's the loneliest of all HoleyFocusLists.
<>import ListIs
HoleyFocusList.empty
|> HoleyFocusList.joinParts
--> ListIs.emptyA HoleyFocusList with a single focussed item in it, nothing before and after it.
<🍊>import ListIs
HoleyFocusList.only "wat"
|> HoleyFocusList.current
--> "wat"
HoleyFocusList.only "wat"
|> HoleyFocusList.joinParts
--> ListIs.only "wat"The current focussed item in the HoleyFocusList.
🍍 🍓 <🍊> 🍉 🍇 -> 🍊HoleyFocusList.only "hi there"
|> HoleyFocusList.current
--> "hi there"
HoleyFocusList.only 1
|> HoleyFocusList.append [ 2, 3, 4 ]
|> HoleyFocusList.last
|> HoleyFocusList.current
--> 4The items before the location of the focus in the HoleyFocusList.
🍍 🍓) <🍊> 🍉 🍇HoleyFocusList.only 0
|> HoleyFocusList.append [ 1, 2, 3 ]
|> HoleyFocusList.next
|> Maybe.andThen HoleyFocusList.next
|> Maybe.map HoleyFocusList.before
--> Just [ 0, 1 ]The items after the current focussed location in the HoleyFocusList.
🍍 🍓 <🍊> (🍉 🍇HoleyFocusList.only 0
|> HoleyFocusList.append [ 1, 2, 3 ]
|> HoleyFocusList.next
|> Maybe.map HoleyFocusList.after
--> Just [ 2, 3 ]Move the focus of the HoleyFocusList to the next item, if there is one.
<🍊> 🍉 🍇 -> 🍊 <🍉> 🍇HoleyFocusList.only 0
|> HoleyFocusList.append [ 1, 2, 3 ]
|> HoleyFocusList.next
|> Maybe.map HoleyFocusList.current
--> Just 1This also works from within holes:
🍊 <> 🍉 🍇 -> 🍊 <🍉> 🍇HoleyFocusList.empty
|> HoleyFocusList.insertAfter "foo"
|> HoleyFocusList.next
--> Just (HoleyFocusList.only "foo")If there is no next item, the result is Nothing.
HoleyFocusList.empty
|> HoleyFocusList.next
--> Nothing
HoleyFocusList.only 0
|> HoleyFocusList.append [ 1, 2, 3 ]
|> HoleyFocusList.last
|> HoleyFocusList.next
--> NothingMove the focus of the HoleyFocusList to the previous item, if there is one.
🍊 <🍉> 🍇 -> <🍊> 🍉 🍇HoleyFocusList.empty |> HoleyFocusList.previous
--> Nothing
HoleyFocusList.only "hello"
|> HoleyFocusList.append [ "holey", "world" ]
|> HoleyFocusList.last
|> HoleyFocusList.previous
|> Maybe.map HoleyFocusList.current
--> Just "holey"This also works from within holes:
🍊 🍉 <> 🍇 -> 🍊 <🍉> 🍇HoleyFocusList.empty
|> HoleyFocusList.insertBefore "foo"
|> HoleyFocusList.previous
--> Just (HoleyFocusList.only "foo")Move the HoleyFocusList to the hole right after the current item. A hole is a whole
lot of nothingness, so it's always there.
🍍 <🍊> 🍉 -> 🍍 🍊 <> 🍉import ListIs
HoleyFocusList.only "hello"
|> HoleyFocusList.append [ "world" ]
|> HoleyFocusList.nextHole
|> HoleyFocusList.plug "holey"
|> HoleyFocusList.joinParts
--> ListIs.fromCons "hello" [ "holey", "world" ]Move the HoleyFocusList to the hole right before the current item. Feel free to plug
that hole right up!
🍍 <🍊> 🍉 -> 🍍 <> 🍊 🍉import ListIs
HoleyFocusList.only "world"
|> HoleyFocusList.previousHole
|> HoleyFocusList.plug "hello"
|> HoleyFocusList.joinParts
--> ListIs.fromCons "hello" [ "world" ]Focus the first item in the HoleyFocusList.
🍍 🍓 <🍊> 🍉 -> <🍍> 🍓 🍊 🍉HoleyFocusList.only 1
|> HoleyFocusList.append [ 2, 3, 4 ]
|> HoleyFocusList.prepend [ 4, 3, 2 ]
|> HoleyFocusList.first
|> HoleyFocusList.current
--> 4Focus the last item in the HoleyFocusList.
🍓 <🍊> 🍉 🍇 -> 🍓 🍊 🍉 <🍇>HoleyFocusList.only 1
|> HoleyFocusList.append [ 2, 3, 4 ]
|> HoleyFocusList.last
|> HoleyFocusList.current
--> 4
HoleyFocusList.only 1
|> HoleyFocusList.append [ 2, 3, 4 ]
|> HoleyFocusList.last
|> HoleyFocusList.before
--> [ 1, 2, 3 ]Focus the hole before the first item. Remember that holes surround everything!
🍍 🍓 <🍊> 🍉 -> <> 🍍 🍓 🍊 🍉import ListIs
HoleyFocusList.only 1 -- <1>
|> HoleyFocusList.append [ 3, 4 ] -- <1> 3 4
|> HoleyFocusList.nextHole -- 1 <> 3 4
|> HoleyFocusList.plug 2 -- 1 <2> 3 4
|> HoleyFocusList.beforeFirst -- <> 1 2 3 4
|> HoleyFocusList.plug 0 -- <0> 1 2 3 4
|> HoleyFocusList.joinParts
--> ListIs.fromCons 0 [ 1, 2, 3, 4 ]Focus the hole after the end of the HoleyFocusList. Into the nothingness.
🍓 <🍊> 🍉 -> 🍓 🍊 🍉 <>import ListIs
HoleyFocusList.only 1 -- <1>
|> HoleyFocusList.append [ 2, 3 ] -- <1> 2 3
|> HoleyFocusList.afterLast -- 1 2 3 <>
|> HoleyFocusList.plug 4 -- 1 2 3 <4>
|> HoleyFocusList.joinParts
--> ListIs.fromCons 1 [ 2, 3, 4 ]Find the first item in the HoleyFocusList the matches a predicate, returning a
HoleyFocusList focussed on that item if it was found.
This start from the current focussed location and searches towards the end.
HoleyFocusList.only 4
|> HoleyFocusList.append [ 2, -1, 0, 3 ]
|> HoleyFocusList.findForward (\item -> item < 0)
|> Maybe.map HoleyFocusList.current
--> Just -1
HoleyFocusList.only -4
|> HoleyFocusList.append [ 2, -1, 0, 3 ]
|> HoleyFocusList.findForward (\item -> item < 0)
|> Maybe.map HoleyFocusList.current
--> Just -4Find the first item in the HoleyFocusList matching a predicate, moving backwards
from the current position.
HoleyFocusList.only 4
|> HoleyFocusList.prepend [ 2, -1, 0, 3 ]
|> HoleyFocusList.findBackward (\item -> item < 0)
|> Maybe.map HoleyFocusList.current
--> Just -1Put items to the end of the HoleyFocusList. After anything else.
🍒🍋
🍓 <🍊> 🍉 🍇 ↓/import ListIs
HoleyFocusList.only 123
|> HoleyFocusList.append [ 456 ]
|> HoleyFocusList.append [ 789, 0 ]
|> HoleyFocusList.joinParts
--> ListIs.fromCons 123 [ 456, 789, 0 ]Put items to the beginning of the HoleyFocusList. Before anything else.
🍒🍋
\↓ 🍍 🍓 <🍊> 🍉import ListIs
HoleyFocusList.only 1
|> HoleyFocusList.append [ 2, 3, 4 ]
|> HoleyFocusList.last
|> HoleyFocusList.prepend [ 5, 6, 7 ]
|> HoleyFocusList.joinParts
--> ListIs.fromCons 5 [ 6, 7, 1, 2, 3, 4 ]If an item is focussed in the HoleyFocusList, apply a function to it.
import ListIs
HoleyFocusList.only "first"
|> HoleyFocusList.prepend [ "zeroth" ]
|> HoleyFocusList.append [ "second", "third" ]
|> HoleyFocusList.mapCurrent String.toUpper
|> HoleyFocusList.joinParts
--> ListIs.fromCons "zeroth" [ "FIRST", "second", "third" ]Fill in or replace the focussed thing in the HoleyFocusList.
🍓 <?> 🍉 -> 🍓 <🍒> 🍉import ListIs
HoleyFocusList.empty
|> HoleyFocusList.insertBefore "🍓" -- "🍓" <>
|> HoleyFocusList.insertAfter "🍉" -- "🍓" <> "🍉"
|> HoleyFocusList.plug "🍒" -- "🍓" <"🍒"> "🍉"
|> HoleyFocusList.joinParts
--> ListIs.fromCons "🍓" [ "🍒", "🍉" ]Punch a hole into the HoleyFocusList by removing the focussed thing.
🍓 <?> 🍉 -> 🍓 <> 🍉HoleyFocusList.only "hello"
|> HoleyFocusList.append [ "holey", "world" ]
|> HoleyFocusList.next
|> Maybe.map HoleyFocusList.remove
|> Maybe.map HoleyFocusList.toList
--> Just [ "hello", "world" ]Apply a function to all items coming before the current focussed location.
import ListIs
HoleyFocusList.only "second"
|> HoleyFocusList.prepend [ "zeroth", "first" ]
|> HoleyFocusList.mapBefore String.toUpper
|> HoleyFocusList.joinParts
--> ListIs.fromCons "ZEROTH" [ "FIRST", "second" ]Apply a function to all items coming after the current focussed location.
import ListIs
HoleyFocusList.only "zeroth"
|> HoleyFocusList.append [ "first", "second" ]
|> HoleyFocusList.mapAfter String.toUpper
|> HoleyFocusList.joinParts
--> ListIs.fromCons "zeroth" [ "FIRST", "SECOND" ]Insert an item after the focussed location.
🍒
🍓 <🍊> ↓ 🍉 🍇import ListIs
HoleyFocusList.only 123
|> HoleyFocusList.append [ 789 ]
|> HoleyFocusList.insertAfter 456
|> HoleyFocusList.joinParts
--> ListIs.fromCons 123 [ 456, 789 ]Insert multiple items using squeezeInAfter.
Insert an item before the focussed location.
🍒
🍍 🍓 ↓ <🍊> 🍉import ListIs
HoleyFocusList.only 123
|> HoleyFocusList.insertBefore 456
|> HoleyFocusList.joinParts
--> ListIs.fromCons 456 [ 123 ]Insert multiple items using squeezeInBefore.
Prepend items directly before the focussed location in the HoleyFocusList.
🍒🍋
🍍 🍓 \↓/ <🍊> 🍉import ListIs
HoleyFocusList.only 0
|> HoleyFocusList.squeezeInBefore [ -5, -4 ]
|> HoleyFocusList.squeezeInBefore [ -3, -2, -1 ]
|> HoleyFocusList.joinParts
--> ListIs.fromCons -5 [ -4, -3, -2, -1, 0 ]Append items directly after the focussed location in the HoleyFocusList.
🍒🍋
🍓 <🍊> \↓/ 🍉 🍇import ListIs
HoleyFocusList.only 0
|> HoleyFocusList.squeezeInAfter [ 4, 5 ]
|> HoleyFocusList.squeezeInAfter [ 1, 2, 3 ]
|> HoleyFocusList.joinParts
--> ListIs.fromCons 0 [ 1, 2, 3, 4, 5 ]Execute a function on every item in the HoleyFocusList.
import ListIs
HoleyFocusList.only "first"
|> HoleyFocusList.prepend [ "zeroth" ]
|> HoleyFocusList.append [ "second", "third" ]
|> HoleyFocusList.map String.toUpper
|> HoleyFocusList.joinParts
--> ListIs.fromCons "ZEROTH" [ "FIRST", "SECOND", "THIRD" ]Apply multiple different functions on the parts of a HoleyFocusList - what
comes before, what comes after, and the current item if there is one.
import ListIs
HoleyFocusList.only "first"
|> HoleyFocusList.append [ "second" ]
|> HoleyFocusList.nextHole
|> HoleyFocusList.plug "one-and-a-halfth"
|> HoleyFocusList.mapParts
{ before = (++) "before: "
, current = (++) "current: "
, after = (++) "after: "
}
|> HoleyFocusList.joinParts
--> ListIs.fromCons
--> "before: first"
--> [ "current: one-and-a-halfth"
--> , "after: second"
--> ]Flattens the HoleyFocusList into a ListIs:
import ListIs
HoleyFocusList.empty
|> HoleyFocusList.joinParts
--> ListIs.empty
HoleyFocusList.only 123
|> HoleyFocusList.append [ 789 ]
|> HoleyFocusList.nextHole
|> HoleyFocusList.plug 456
|> HoleyFocusList.joinParts
--> ListIs.fromCons 123 [ 456, 789 ]the type information gets carried over, so
Item -> ListIs.NotEmpty
CanBe hole_ () -> CanBe empty_ ()Flattens the HoleyFocusList into a list:
HoleyFocusList.only 456
|> HoleyFocusList.prepend [ 123 ]
|> HoleyFocusList.append [ 789 ]
|> HoleyFocusList.toList
--> [ 123, 456, 789 ]Only use this if you need a list in the end.
Otherwise, use joinParts to preserve some information about its length.
Find out if the current focussed thing is an item.
import MaybeIs
HoleyFocusList.only 3
|> HoleyFocusList.append [ 2, 1 ]
|> HoleyFocusList.nextHole
|> HoleyFocusList.focussesItem
--> MaybeIs.nothingWhen using a HoleyFocusList Item ... argument,
its type can't be unified with non-Item lists.
Please read more at MaybeIs.branchableType.
Represents a special kind of list with items of type
a.The type
focuscan be🍍 🍓 <🍊> 🍉 🍇: useItemto require such an argument🍍 🍓 <?> 🍉 🍇: use a type variable to require such an argument<?>means both are possible:🍍 🍓 <> 🍉 🍇: a hole between items ... Heh.🍍 🍓 <🍊> 🍉 🍇