lue-bird/elm-emptiness-typed/8.0.0

NOTE: the latest version is 9.2.1

Stack

📚 An emptiable or non-empty structure where top, topRemove, onTopLay are O(n)

type Stacked element
= TopBelow ( element, List element )

The representation of a non-empty stack on the Filled case. top, topRemove, onTopLay are O(n)

in arguments

Emptiable (StackFilled ...) Never → stack is non-empty:

top : Emptiable (Stacked element) Never -> element

in results

Emptiable (StackFilled ...)Possibly Empty → stack could be empty

fromList : List element -> Emptiable (Stacked element) Possibly

We can treat it like any Emptiable:

import Emptiable exposing (Emptiable(..), filled, fillMap)
import Possibly exposing (Possibly)
import Stack exposing (Stacked, top, onTopLay)


Emptiable.empty |> onTopLay "cherry" -- works


toList : Empty possiblyOrNever_ (Stacked element) -> List element
toList =
    \stack ->
        case stack of
            Filled (Stack.TopBelow ( top_, below )) ->
                top_ :: below


            Empty _ ->
                []


[ "hi", "there" ] -- comes in as an argument
    |> Stack.fromList
    |> fillMap (filled >> top)
--: Emptiable String Possibly

create

Emptiable.empty to create an Empty Possibly stack

only : element -> Emptiable (Stacked element) never_

A stack with just 1 single element

import Emptiable
import Stack exposing (onTopLay)


Stack.only ":)"
--> Emptiable.empty |> onTopLay ":)"
topBelow : element -> List element -> Emptiable (Stacked element) never_

A stack from a top element and a List of elements below

fromTopBelow : ( element, List element ) -> Emptiable (Stacked element) never_

Take a tuple ( top, List belowElement ) from another source like turboMaCk/non-empty-list-alias and convert it to an Emptiable (StackTopBelow top belowElement) never_

Use topBelow if you don't already have a tuple to convert from

fromList : List element -> Emptiable (Stacked element) Possibly

Convert a List element to a Empty Possibly (Stacked element). The Lists head becomes top, its tail is glued below

import Possibly exposing (Possibly)
import Emptiable
import Stack exposing (topBelow)


[] |> Stack.fromList
--> Emptiable.empty


[ "hello", "emptiness" ] |> Stack.fromList
--> topBelow "hello" [ "emptiness" ]
--: Empty Possibly (Stacked String)

When constructing from known elements, always prefer

import Stack exposing (topBelow)


topBelow "hello" [ "emptiness" ]
fromString : String -> Emptiable (Stacked Char) Possibly

Convert to an Emptiable (Stacked Char) Possibly. The Strings head becomes top, its tail is glued below

import Possibly exposing (Possibly)
import Emptiable
import Stack exposing (topBelow)


"" |> Stack.fromText
--> Emptiable.empty


"hello" |> Stack.fromText
--> topBelow 'h' [ 'e', 'l', 'l', 'o' ]
--: Emptiable (Stacked Char) Possibly

When constructing from known elements, always prefer

import Stack exposing (topBelow)


onTopLay 'h' ("ello" |> Stack.fromText)

scan

top : Emptiable (Stacked element) Never -> element

The first value

import Stack exposing (top, onTopLay)


Stack.only 3
    |> onTopLay 2
    |> top
--> 2
length : Emptiable (Stacked element_) possiblyOrNever_ -> Int

How many element there are

import Stack exposing (onTopLay)


Stack.only 3
    |> onTopLay 2
    |> Stack.length
--> 2

O(n) like List.length

topRemove brings out everything below the top

alter

element
-> Emptiable (Stacked element) possiblyOrNever_
-> Emptiable (Stacked element) never_

Add an element to the front

import Emptiable
import Stack exposing (topBelow, onTopLay)


topBelow 2 [ 3 ] |> onTopLay 1
--> topBelow 1 [ 2, 3 ]


Emptiable.empty |> onTopLay 1
--> Stack.only 1
Emptiable (Stacked element) Never
-> Emptiable (Stacked element) Possibly

Everything after the first value

import Stack exposing (topBelow, onTopLay, onTopStack, topRemove)


Stack.only 2
    |> onTopLay 3
    |> onTopStack (topBelow 1 [ 0 ])
    |> topRemove
--> topBelow 0 [ 3, 2 ]
--: Emptiable (Stacked number_) Possibly
Emptiable (Stacked element) possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNever

Flip the order of the elements

import Stack exposing (topBelow)


topBelow "l" [ "i", "v", "e" ]
    |> Stack.reverse
--> topBelow "e" [ "v", "i", "l" ]

filter

(Stacked (Emptiable element possiblyOrNever))
possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNever

Keep all filled elements and drop all empty elements

import Emptiable exposing (filled)
import Stack exposing (topBelow)


topBelow Emptiable.empty [ Emptiable.empty ]
    |> Stack.fills
--> Emptiable.empty


topBelow (filled 1) [ Emptiable.empty, filled 3 ]
    |> Stack.fills
--> topBelow 1 [ 3 ]

As you can see, if only the top is fill a value, the result is non-empty

glue

List element
-> Emptiable (Stacked element) possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNever

Put the elements of a List on top

import Stack exposing (topBelow, onTopStack)


topBelow 1 [ 2 ]
    |> Stack.onTopGlue [ -1, 0 ]
--> topBelow -1 [ 0, 1, 2 ]

onTopGlue only when the piped stack food is already ... Never. Glue a stack on top with

  • onTopStack takes on the possiblyOrNever type of the piped food
  • onTopStackAdapt takes on the possiblyOrNever type of the argument
Emptiable (Stacked element) possiblyOrNeverAppended_
-> Emptiable (Stacked element) possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNever

Glue the elements of a stack to the end of the stack

import Stack exposing (topBelow, onTopStack)


topBelow 1 [ 2 ]
    |> onTopStack (topBelow -1 [ 0 ])
--> topBelow -1 [ 0, 1, 2 ]
  • onTopStack takes on the possiblyOrNever type of the piped food
  • onTopStackAdapt takes on the possiblyOrNever type of the argument
Emptiable (Stacked element) possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNeverIn_
-> Emptiable (Stacked element) possiblyOrNever

Glue the elements of a ... Empty possiblyOrNever/Never Stack to the top of this Stack

import Emptiable
import Stack exposing (topBelow, onTopStack, onTopStackAdapt)


Emptiable.empty
    |> onTopStackAdapt (topBelow 1 [ 2 ])
    |> onTopStack (topBelow -2 [ -1, 0 ])
--> topBelow -2 [ -1, 0, 1, 2 ]
  • onTopStack takes on the possiblyOrNever type of the piped food
  • onTopStackAdapt takes on the possiblyOrNever type of the argument
(Stacked (Emptiable (Stacked element) possiblyOrNever))
possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNever

Glue together a bunch of stacks

import Emptiable
import Stack exposing (topBelow)


topBelow
    (topBelow 0 [ 1 ])
    [ topBelow 10 [ 11 ]
    , Emptiable.empty
    , topBelow 20 [ 21, 22 ]
    ]
    |> Stack.flatten
--> topBelow 0 [ 1, 10, 11, 20, 21, 22 ]

For this to return a non-empty stack, all stacks must be non-empty

transform

map :
({ index : Int } -> element -> elementMapped)
-> Emptiable (Stacked element) possiblyOrNever
-> Emptiable (Stacked elementMapped) possiblyOrNever

Change every element based on its current value and { index }

import Stack exposing (topBelow)


topBelow 1 [ 4, 9 ]
    |> Stack.map (\_ -> negate)
--> topBelow -1 [ -4, -9 ]


topBelow 1 [ 2, 3, 4 ]
    |> Stack.map (\{ index } n -> index * n)
--> topBelow 0 [ 2, 6, 12 ]
and :
Emptiable (Stacked anotherElement) possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNever
-> Emptiable (Stacked ( element, anotherElement )) possiblyOrNever

Combine its elements with elements of a given stack at the same location. If one stack is longer, the extra elements are dropped

import Stack exposing (topBelow)


topBelow "alice" [ "bob", "chuck" ]
    |> Stack.and (topBelow 2 [ 5, 7, 8 ])
--> topBelow ( "alice", 2 ) [ ( "bob", 5 ), ( "chuck", 7 ) ]


topBelow 4 [ 5, 6 ]
    |> Stack.and (topBelow 1 [ 2, 3 ])
    |> Stack.map (\_ ( n0, n1 ) -> n0 + n1)
--> topBelow 5 [ 7, 9 ]
accumulationValue
-> Direction
-> (element -> accumulationValue -> accumulationValue)
-> Emptiable (Stacked element) possiblyOrNever_
-> accumulationValue

Reduce in a direction

import Linear exposing (Direction(..))
import Stack exposing (topBelow)


topBelow 'l' [ 'i', 'v', 'e' ]
    |> Stack.foldFrom "" Down String.cons
--> "live"


topBelow 'l' [ 'i', 'v', 'e' ]
    |> Stack.foldFrom "" Up String.cons
--> "evil"

Be aware:

  • Down = indexes decreasing, not: from the top lower
  • Up = indexes increasing, not: from the bottom up
(element -> accumulated)
-> Direction
-> (element -> accumulated -> accumulated)
-> Emptiable (Stacked element) Never
-> accumulated

Fold, starting from one end element transformed to the initial accumulation value, then reducing what's accumulated in a given Direction

import Linear exposing (Direction(..))
import Stack exposing (topBelow)


topBelow 234 [ 345, 543 ]
    |> Stack.foldOnto SetFilled.only Up SetFilled.insert

A simpler version is

Stack.fold =
    Stack.foldOnto identity

Be aware:

  • Down = indexes decreasing, not: from the top lower
  • Up = indexes increasing, not: from the bottom up
Direction
-> (element -> element -> element)
-> Emptiable (Stacked element) Never
-> element

Fold, starting from one end as the initial accumulation value, then reducing what's accumulated in a given Direction

import Linear exposing (Direction(..))
import Stack exposing (topBelow)


topBelow 234 [ 345, 543 ]
    |> Stack.fold Up max
--> 543

Feel limited by the fact that the accumulated value is of the same type as an element? → Stack.foldOnto

Be aware:

  • Down = indexes decreasing, not: from the top lower
  • Up = indexes increasing, not: from the bottom up
sum : Emptiable (Stacked number) possiblyOrNever_ -> number

∑ Total every element number

import Emptiable


topBelow 1 [ 2, 3 ] |> Stack.sum
--> 6


topBelow 1 (List.repeat 5 1) |> Stack.sum
--> 6


Emptiable.empty |> Stack.sum
--> 0
toTopBelow : Emptiable (Stacked element) Never -> ( element, List element )

Convert to a non-empty list tuple ( top, List belowElement ) to be used by another library

import Stack exposing (topBelow, toTopBelow)


topBelow "hi" [ "there", "👋" ]
    |> toTopBelow
--> ( "hi", [ "there", "👋" ] )

Don't use toTopBelow to destructure a stack. Instead: Stack.top, Stack.topRemove

toList : Emptiable (Stacked element) possiblyOrNever_ -> List element

Convert to a List

import Stack exposing (topBelow)


topBelow 1 [ 7 ] |> Stack.toList
--> [ 1, 7 ]

Don't try to use this prematurely. Keeping type information as long as possible is always a win

toString : Emptiable (Stacked Char) possiblyOrNever_ -> String

Convert to a String

import Stack exposing (topBelow)


topBelow 'H' [ 'i' ] |> Stack.toString
--> "Hi"

Don't try to use this prematurely. Keeping type information as long as possible is always a win