lue-bird/elm-emptiness-typed/4.0.0

NOTE: the latest version is 9.2.1

FocusList

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 ListFocusingHole possiblyOrNever item

A special kind of list with elements of type item.

The focus can be

  • 🍍 🍓 <🍊> 🍉 🍇: ListFocusingHole Never

  • 🍍 🍓 <?> 🍉 🍇: ListFocusingHole Possibly

    <?> means both are possible:

    • 🍍 🍓 <> 🍉 🍇: a hole between items ... Heh.
    • 🍍 🍓 <🍊> 🍉 🍇

in arguments

empty : ListFocusingHole Possibly item_

in types

type alias Model =
    WithoutConstructorFunction
        { choice : ListFocusingHole Never Option
        }

where

type alias WithoutConstructorFunction record =
    record

stops the compiler from creating a positional constructor function for Model.

create

empty : ListFocusingHole Possibly item_

An empty FocusList on a hole with nothing before and after it. It's the loneliest of all FocusLists.

<>
import Fillable
import Stack


FocusList.empty
    |> FocusList.toStack
--> Fillable.empty
only : element -> ListFocusingHole never_ element

A FocusList with a single focussed item in it, nothing before and after it.

<🍊>
import Stack


FocusList.only "wat"
    |> FocusList.current
--> "wat"


FocusList.only "wat"
    |> FocusList.toStack
--> Stack.only "wat"

scan

current : ListFocusingHole Never item -> item

The current focussed item.

🍍 🍓 <🍊> 🍉 🍇  ->  🍊
FocusList.only "hi there"
    |> FocusList.current
--> "hi there"


FocusList.only 1
    |> FocusList.append [ 2, 3, 4 ]
    |> FocusList.last
    |> FocusList.current
--> 4
ListFocusingHole possiblyOrNever_ item
-> Empty Possibly (StackFilled item)

The items before the location of the focus.

🍍 🍓) <🍊> 🍉 🍇
import Fillable exposing (Empty, filled)
import Stack exposing (StackFilled, topAndBelow)


FocusList.only 0
    |> FocusList.append [ 1, 2, 3 ]
    |> FocusList.next
    |> Fillable.andThen FocusList.next
    |> Fillable.map FocusList.before
--> filled (topAndBelow 0 [ 1 ])
--: Empty Possibly (Empty Possibly (StackFilled number_))
ListFocusingHole possiblyOrNever_ item
-> Empty Possibly (StackFilled item)

The items after the current focussed location.

🍍 🍓 <🍊> (🍉 🍇
import Fillable exposing (Empty, filled)
import Stack exposing (StackFilled, topAndBelow)


FocusList.only 0
    |> FocusList.append [ 1, 2, 3 ]
    |> FocusList.next
    |> Fillable.map FocusList.after
--> filled (topAndBelow 2 [ 3 ])
--: Empty Possibly (Empty Possibly (StackFilled number_))
nextHole : ListFocusingHole Never item -> ListFocusingHole Possibly item

Move the focus to the hole right after the current item. A hole is a whole lot of nothingness, so it's always there.

🍍 <🍊> 🍉  ->  🍍 🍊 <> 🍉
import Stack exposing (topAndBelow)


FocusList.only "hello"
    |> FocusList.append [ "world" ]
    |> FocusList.nextHole
    |> FocusList.plug "holey"
    |> FocusList.toStack
--> topAndBelow "hello" [ "holey", "world" ]
previousHole : ListFocusingHole Never item -> ListFocusingHole Possibly item

Move the focus to the hole right before the current item. Feel free to plug that hole right up!

🍍 <🍊> 🍉  ->  🍍 <> 🍊 🍉
import Stack


FocusList.only "world"
    |> FocusList.previousHole
    |> FocusList.plug "hello"
    |> FocusList.toStack
--> Stack.topAndBelow "hello" [ "world" ]
ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Focus the first item.

🍍 🍓 <🍊> 🍉  ->  <🍍> 🍓 🍊 🍉
FocusList.only 1
    |> FocusList.append [ 2, 3, 4 ]
    |> FocusList.prepend [ 4, 3, 2 ]
    |> FocusList.first
    |> FocusList.current
--> 4
ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Focus the last item.

🍓 <🍊> 🍉 🍇  ->  🍓 🍊 🍉 <🍇>
import Stack exposing (topAndBelow)


FocusList.only 1
    |> FocusList.append [ 2, 3, 4 ]
    |> FocusList.last
    |> FocusList.current
--> 4


FocusList.only 1
    |> FocusList.append [ 2, 3, 4 ]
    |> FocusList.last
    |> FocusList.before
--> topAndBelow 1 [ 2, 3 ]
--: Empty Possibly (StackFilled number_)
ListFocusingHole possiblyOrNever_ item
-> ListFocusingHole Possibly item

Focus the hole before the first item. Remember that holes surround everything!

🍍 🍓 <🍊> 🍉  ->  <> 🍍 🍓 🍊 🍉
import Stack


FocusList.only 1                 -- <1>
    |> FocusList.append [ 3, 4 ] -- <1> 3 4
    |> FocusList.nextHole        -- 1 <> 3 4
    |> FocusList.plug 2          -- 1 <2> 3 4
    |> FocusList.beforeFirst     -- <> 1 2 3 4
    |> FocusList.plug 0          -- <0> 1 2 3 4
    |> FocusList.toStack
--> Stack.topAndBelow 0 [ 1, 2, 3, 4 ]
ListFocusingHole possiblyOrNever_ item
-> ListFocusingHole Possibly item

Focus the hole after the end. Into the nothingness.

🍓 <🍊> 🍉  ->  🍓 🍊 🍉 <>
import Stack


FocusList.only 1                 -- <1>
    |> FocusList.append [ 2, 3 ] -- <1> 2 3
    |> FocusList.afterLast       -- 1 2 3 <>
    |> FocusList.plug 4          -- 1 2 3 <4>
    |> FocusList.toStack
--> Stack.topAndBelow 1 [ 2, 3, 4 ]
(item -> Bool)
-> ListFocusingHole possiblyOrNever_ item
-> Empty Possibly (ListFocusingHole never_ item)

Find the first item in the FocusList the matches a predicate, returning a FocusList focussed on that item if it was found.

This start from the current focussed location and searches towards the end.

import Fillable exposing (filled)


FocusList.only 4
    |> FocusList.append [ 2, -1, 0, 3 ]
    |> FocusList.findForward (\item -> item < 0)
    |> Fillable.map FocusList.current
--> filled -1


FocusList.only -4
    |> FocusList.append [ 2, -1, 0, 3 ]
    |> FocusList.findForward (\item -> item < 0)
    |> Fillable.map FocusList.current
--> filled -4
(item -> Bool)
-> ListFocusingHole possiblyOrNever_ item
-> Empty Possibly (ListFocusingHole never_ item)

Find the first item matching a predicate, moving backwards from the current position.

import Fillable exposing (filled)


FocusList.only 4
    |> FocusList.prepend [ 2, -1, 0, 3 ]
    |> FocusList.findBackward (\item -> item < 0)
    |> Fillable.map FocusList.current
--> filled -1

alter

Empty stackPossiblyOrNever_ (StackFilled item)
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Put a stack of items to the end after anything else.

              🍒🍋
🍓 <🍊> 🍉 🍇 ↓/
import Stack exposing (topAndBelow)


FocusList.only 123
    |> FocusList.append [ 456 ]
    |> FocusList.append [ 789, 0 ]
    |> FocusList.toStack
--> topAndBelow 123 [ 456, 789, 0 ]
List item
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Put items to the end after anything else.

              🍒🍋
🍓 <🍊> 🍉 🍇 ↓/
import Stack exposing (topAndBelow)


FocusList.only 123
    |> FocusList.append [ 456 ]
    |> FocusList.append [ 789, 0 ]
    |> FocusList.toStack
--> topAndBelow 123 [ 456, 789, 0 ]
Empty stackPossiblyOrNever_ (StackFilled item)
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Put a stack of items to the beginning before anything else.

🍒🍋
 \↓ 🍍 🍓 <🍊> 🍉
import Stack exposing (topAndBelow)


FocusList.only 1
    |> FocusList.append [ 2, 3, 4 ]
    |> FocusList.last
    |> FocusList.prependStack (topAndBelow 5 [ 6, 7 ])
    |> FocusList.toStack
--> topAndBelow 5 [ 6, 7, 1, 2, 3, 4 ]
List item
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Put items to the beginning before anything else.

🍒🍋
 \↓ 🍍 🍓 <🍊> 🍉
import Stack exposing (topAndBelow)


FocusList.only 1
    |> FocusList.append [ 2, 3, 4 ]
    |> FocusList.last
    |> FocusList.prepend [ 5, 6, 7 ]
    |> FocusList.toStack
--> topAndBelow 5 [ 6, 7, 1, 2, 3, 4 ]

at the focus

(item -> item)
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

If an item is focussed, alter it based on its current value.

import Stack


FocusList.only "first"
    |> FocusList.prepend [ "zeroth" ]
    |> FocusList.append [ "second", "third" ]
    |> FocusList.alterCurrent String.toUpper
    |> FocusList.toStack
--> Stack.topAndBelow "zeroth" [ "FIRST", "second", "third" ]
item
-> ListFocusingHole possiblyOrNever_ item
-> ListFocusingHole never_ item

Fill in or replace the focussed thing in the FocusList.

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


FocusList.empty
    |> FocusList.insertBefore "🍓" -- "🍓" <>
    |> FocusList.insertAfter "🍉"  -- "🍓" <> "🍉"
    |> FocusList.plug "🍒"         -- "🍓" <"🍒"> "🍉"
    |> FocusList.toStack
--> Stack.topAndBelow "🍓" [ "🍒", "🍉" ]
ListFocusingHole possiblyOrNever_ item
-> ListFocusingHole Possibly item

Punch a hole by removing the focussed thing.

🍓 <?> 🍉  ->  🍓 <> 🍉
import Fillable exposing (filled)


FocusList.only "hello"
    |> FocusList.append [ "holey", "world" ]
    |> FocusList.next
    |> Fillable.map FocusList.remove
    |> Fillable.map FocusList.toList
--> filled [ "hello", "world" ]

around the focus

(item -> item)
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Apply a function to all items coming before the current focussed location.

import Stack


FocusList.only "second"
    |> FocusList.prepend [ "zeroth", "first" ]
    |> FocusList.alterBefore String.toUpper
    |> FocusList.toStack
--> Stack.topAndBelow "ZEROTH" [ "FIRST", "second" ]
(item -> item)
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Apply a function to all items coming after the current focussed location.

import Stack


FocusList.only "zeroth"
    |> FocusList.append [ "first", "second" ]
    |> FocusList.alterAfter String.toUpper
    |> FocusList.toStack
--> Stack.topAndBelow "zeroth" [ "FIRST", "SECOND" ]
item
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Insert an item after the focussed location.

        🍒
🍓 <🍊> ↓ 🍉 🍇
import Stack


FocusList.only 123
    |> FocusList.append [ 789 ]
    |> FocusList.insertAfter 456
    |> FocusList.toStack
--> Stack.topAndBelow 123 [ 456, 789 ]

Insert multiple items using squeezeInAfter.

item
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Insert an item before the focussed location.

      🍒
🍍 🍓 ↓ <🍊> 🍉
import Stack


FocusList.only 123
    |> FocusList.insertBefore 456
    |> FocusList.toStack
--> Stack.topAndBelow 456 [ 123 ]

Insert multiple items using squeezeInBefore.

Empty Possibly (StackFilled item)
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Prepend a Stack of items directly before the focussed location.

      🍒🍋
🍍 🍓 \↓/ <🍊> 🍉
import Stack exposing (topAndBelow)


FocusList.only 0
    |> FocusList.squeezeStackInBefore
        (topAndBelow -5 [ -4 ])
    |> FocusList.squeezeStackInBefore
        (topAndBelow -3 [ -2, -1 ])
    |> FocusList.toStack
--> topAndBelow -5 [ -4, -3, -2, -1, 0 ]
List item
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Prepend items directly before the focussed location.

      🍒🍋
🍍 🍓 \↓/ <🍊> 🍉
import Stack exposing (topAndBelow)


FocusList.only 0
    |> FocusList.squeezeInBefore [ -5, -4 ]
    |> FocusList.squeezeInBefore [ -3, -2, -1 ]
    |> FocusList.toStack
--> topAndBelow -5 [ -4, -3, -2, -1, 0 ]
Empty Possibly (StackFilled item)
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Append a Stack of items directly after the focussed location.

        🍒🍋
🍓 <🍊> \↓/ 🍉 🍇
import Stack exposing (topAndBelow)


FocusList.only 0
    |> FocusList.squeezeStackInAfter
        (topAndBelow 4 [ 5 ])
    |> FocusList.squeezeStackInAfter
        (topAndBelow 1 [ 2, 3 ])
    |> FocusList.toStack
--> topAndBelow 0 [ 1, 2, 3, 4, 5 ]
List item
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever item

Append items directly after the focussed location.

        🍒🍋
🍓 <🍊> \↓/ 🍉 🍇
import Stack exposing (topAndBelow)


FocusList.only 0
    |> FocusList.squeezeInAfter [ 4, 5 ]
    |> FocusList.squeezeInAfter [ 1, 2, 3 ]
    |> FocusList.toStack
--> topAndBelow 0 [ 1, 2, 3, 4, 5 ]

transform

map :
(item -> mappedItem)
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever mappedItem

Change every item based on its current value.

import Stack


FocusList.only "first"
    |> FocusList.prepend [ "zeroth" ]
    |> FocusList.append [ "second", "third" ]
    |> FocusList.map String.toUpper
    |> FocusList.toStack
--> Stack.topAndBelow "ZEROTH" [ "FIRST", "SECOND", "THIRD" ]
{ before : item -> mappedItem
, current : item -> mappedItem
, after : item -> mappedItem
}
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNever mappedItem

Apply multiple different functions on the parts of a FocusList- what comes before, what comes after, and the current item if there is one.

import Stack


FocusList.only "first"
    |> FocusList.append [ "second" ]
    |> FocusList.nextHole
    |> FocusList.plug "one-and-a-halfth"
    |> FocusList.mapParts
        { before = (++) "before: "
        , current = (++) "current: "
        , after = (++) "after: "
        }
    |> FocusList.toStack
--> Stack.topAndBelow
-->     "before: first"
-->     [ "current: one-and-a-halfth"
-->     , "after: second"
-->     ]
ListFocusingHole possiblyOrNever item
-> Empty possiblyOrNever (StackFilled item)

Flattens the FocusList into a Stack:

import Fillable
import Stack


FocusList.empty
    |> FocusList.toStack
--> Fillable.empty


FocusList.only 123
    |> FocusList.append [ 789 ]
    |> FocusList.nextHole
    |> FocusList.plug 456
    |> FocusList.toStack
--> Stack.topAndBelow 123 [ 456, 789 ]

the type information gets carried over, so

Item -> Stack.Never
Possibly
toList : ListFocusingHole possiblyOrNever_ item -> List item

Converts it to a flattened list:

FocusList.only 456
    |> FocusList.prepend [ 123 ]
    |> FocusList.append [ 789 ]
    |> FocusList.toList
--> [ 123, 456, 789 ]

Only use this if you need a list in the end. Otherwise, use toStack to preserve some information about its length.

ListFocusingHole possiblyOrNever item
-> Empty possiblyOrNever (ListFocusingHole never_ item)

Fillable.empty if the current focussed thing is a hole, Fillable.filled if it is an item.

import Fillable


FocusList.only 3
    |> FocusList.append [ 2, 1 ]
    |> FocusList.nextHole
    |> FocusList.focusingItem
--> Fillable.empty

type-level

(possiblyOrNever -> possiblyOrNeverAdapted)
-> ListFocusingHole possiblyOrNever item
-> ListFocusingHole possiblyOrNeverAdapted item

Change the possiblyOrNever type.

  • A ListFocusingHole possiblyOrNever can't be used as a ListFocusingHole Possibly?

    import Possibly exposing (Possible)
    
    
    FocusList.adaptType (always Possible)
  • A ListFocusingHole Never can't be unified with Possibly or ListFocusingHole possiblyOrNever?

    FocusList.adaptType never

Please read more at Fillable.adaptType.