lue-bird/elm-emptiness-typed/2.0.3

NOTE: the latest version is 9.2.1

HoleyFocusList

A list zipper that can also focus on a hole between items.

  1. 🔎 focus on a hole between two items
  2. 🔌 plug that hole with a value
  3. 💰 profit

types

type HoleyFocusList focus a

Represents a special kind of list with items of type a.

The type focus can be

  • 🍍 🍓 <🍊> 🍉 🍇: use Item to require such an argument

  • 🍍 🍓 <?> 🍉 🍇: use a type variable to require such an argument

    <?> means both are possible:

    • 🍍 🍓 <> 🍉 🍇: a hole between items ... Heh.
    • 🍍 🍓 <🍊> 🍉 🍇
type alias Item =
CanBe { hole : () } Never

A HoleyFocusList Item a is focussed on an element of type a.

🍍 🍓 <🍊> 🍉 🍇

create

empty : HoleyFocusList (CanBe hole_ ()) 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.empty
only : a -> HoleyFocusList item_ a

A 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"

scan

current : HoleyFocusList Item a -> a

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
--> 4
before : HoleyFocusList focus_ a -> List a

The 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 ]
after : HoleyFocusList focus_ a -> List a

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 ]
nextHole : HoleyFocusList Item a -> HoleyFocusList (CanBe hole_ ()) a

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" ]
first : HoleyFocusList focus a -> HoleyFocusList focus a

Focus the first item in the HoleyFocusList.

🍍 🍓 <🍊> 🍉  ->  <🍍> 🍓 🍊 🍉
HoleyFocusList.only 1
    |> HoleyFocusList.append [ 2, 3, 4 ]
    |> HoleyFocusList.prepend [ 4, 3, 2 ]
    |> HoleyFocusList.first
    |> HoleyFocusList.current
--> 4
last : HoleyFocusList focus a -> HoleyFocusList focus a

Focus 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 ]
beforeFirst : HoleyFocusList focus_ a -> HoleyFocusList (CanBe hole_ ()) a

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 ]
afterLast : HoleyFocusList focus_ a -> HoleyFocusList (CanBe hole_ ()) a

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 ]
(a -> Bool)
-> HoleyFocusList focus_ a
-> Maybe (HoleyFocusList item_ a)

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 -4
(a -> Bool)
-> HoleyFocusList focus_ a
-> Maybe (HoleyFocusList item_ a)

Find 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 -1

modify

append : List a -> HoleyFocusList focus a -> HoleyFocusList focus a

Put 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 ]
prepend : List a -> HoleyFocusList focus a -> HoleyFocusList focus a

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 ]

modify the focus

(a -> a)
-> HoleyFocusList (CanBe hole_ yesOrNever) a
-> HoleyFocusList (CanBe mappedHole_ yesOrNever) a

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" ]
plug : a -> HoleyFocusList holeOrItem_ a -> HoleyFocusList item_ a

Fill in or replace the focussed thing in the HoleyFocusList.

🍓 <?> 🍉  ->  🍓 <🍒> 🍉
import ListIs


HoleyFocusList.empty
    |> HoleyFocusList.insertBefore "🍓" -- "🍓" <>
    |> HoleyFocusList.insertAfter "🍉"  -- "🍓" <> "🍉"
    |> HoleyFocusList.plug "🍒"         -- "🍓" <"🍒"> "🍉"
    |> HoleyFocusList.joinParts
--> ListIs.fromCons "🍓" [ "🍒", "🍉" ]
remove : HoleyFocusList focus_ a -> HoleyFocusList (CanBe hole_ ()) a

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" ]

modify around the focus

mapBefore : (a -> a) -> HoleyFocusList focus a -> HoleyFocusList focus a

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" ]
mapAfter : (a -> a) -> HoleyFocusList focus a -> HoleyFocusList focus a

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" ]
insertAfter : a -> HoleyFocusList focus a -> HoleyFocusList focus a

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.

insertBefore : a -> HoleyFocusList focus a -> HoleyFocusList focus a

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.

squeezeInBefore : List a -> HoleyFocusList focus a -> HoleyFocusList focus a

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 ]
squeezeInAfter : List a -> HoleyFocusList focus a -> HoleyFocusList focus a

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 ]

transform

map :
(a -> b)
-> HoleyFocusList (CanBe hole_ yesOrNever) a
-> HoleyFocusList (CanBe mappedHole_ yesOrNever) b

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" ]
{ before : a -> b
, current : a -> b
, after : a -> b
}
-> HoleyFocusList (CanBe hole_ yesOrNever) a
-> HoleyFocusList (CanBe mappedHole_ yesOrNever) b

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"
-->     ]
HoleyFocusList (CanBe holeTag_ yesOrNever) a
-> ListIs (CanBe emptyTag_ yesOrNever) a

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_ ()
toList : HoleyFocusList focus_ a -> List a

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.

type-level

HoleyFocusList (CanBe holeTag_ yesOrNever) a
-> MaybeIs (CanBe emptyTag_ yesOrNever) (HoleyFocusList item_ a)

Find out if the current focussed thing is an item.

import MaybeIs


HoleyFocusList.only 3
    |> HoleyFocusList.append [ 2, 1 ]
    |> HoleyFocusList.nextHole
    |> HoleyFocusList.focussesItem
--> MaybeIs.nothing

When using a HoleyFocusList Item ... argument, its type can't be unified with non-Item lists.

Please read more at MaybeIs.branchableType.