lue-bird/elm-emptiness-typed/7.0.0

NOTE: the latest version is 9.2.1

Stack

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

type alias Stacked element =
StackTopBelow element element

The representation of a non-empty stack on the Filled case. top, topRemove, onTopLay topMap 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.TopDown top_ down) ->
                top_ :: down


            Empty _ ->
                []


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

Most operations also allow a different type for the top element → see StackTopBelow

type StackTopBelow topElement belowTopElement
= TopDown topElement (List belowTopElement)

Stacked with a different type for the top element:

top : Emptiable (StackTopBelow top belowTopElement_) Never -> top

it's the result of:

create

Emptiable.empty to create an Empty Possibly stack

only : top -> Emptiable (StackTopBelow top belowTopElement_) never_

A stack with just 1 single element

import Emptiable
import Stack exposing (onTopLay)


Stack.only ":)"
--> Emptiable.empty |> onTopLay ":)"
top
-> List belowElement
-> Emptiable (StackTopBelow top belowElement) never_

A stack from a top element and a List of elements below going down.

( top, List belowElement )
-> Emptiable (StackTopBelow top belowElement) 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 topDown 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 shoved down below

import Possibly exposing (Possibly)
import Emptiable
import Stack exposing (topDown)


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


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

When constructing from known elements, always prefer

import Stack exposing (topDown)


topDown "hello" [ "emptiness" ]
fromText : String -> Emptiable (Stacked Char) Possibly

Convert a String to a Emptiable (Stacked Char) Possibly. The Strings head becomes top, its tail is shoved down below

import Possibly exposing (Possibly)
import Emptiable
import Stack exposing (topDown)


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


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

When constructing from known elements, always prefer

import Stack exposing (topDown)


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

scan

top : Emptiable (StackTopBelow top belowTop_) Never -> top

The first value

import Stack exposing (top, onTopLay)


Stack.only 3
    |> onTopLay 2
    |> top
--> 2
Emptiable (StackTopBelow top_ belowElement_) 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

newTop
-> Emptiable (Stacked belowElement) possiblyOrNever_
-> Emptiable (StackTopBelow newTop belowElement) never_

Add an element to the front

import Emptiable
import Stack exposing (topDown, onTopLay)


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


Emptiable.empty |> onTopLay 1
--> Stack.only 1
Emptiable (StackTopBelow top_ belowElement) Never
-> Emptiable (Stacked belowElement) Possibly

Everything after the first value

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


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

Flip the order of the elements

import Stack exposing (topDown)


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

filter

(Emptiable topContent possiblyOrNever)
(Emptiable belowElementContent belowPossiblyOrNever_)
)
possiblyOrNever
(StackTopBelow topContent belowElementContent)
possiblyOrNever

Keep all filled elements and drop all empty elements

import Emptiable exposing (filled)
import Stack exposing (topDown)


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


topDown (filled 1) [ Emptiable.empty, filled 3 ]
    |> Stack.fills
--> topDown 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 (topDown, onTopStack)


topDown 1 [ 2 ]
    |> Stack.onTopGlue [ -1, 0 ]
--> topDown -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 (topDown, onTopStack)


topDown 1 [ 2 ]
    |> onTopStack (topDown -1 [ 0 ])
--> topDown -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 (topDown, onTopStack, onTopStackAdapt)


Emptiable.empty
    |> onTopStackAdapt (topDown 1 [ 2 ])
    |> onTopStack (topDown -2 [ -1, 0 ])
--> topDown -2 [ -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) belowTopListsPossiblyOrNever_)
)
possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNever

Glue together a bunch of stacks

import Emptiable
import Stack exposing (topDown)


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

For this to return a non-empty stack, there must be a non-empty top stack

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 (topDown)


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


topDown 1 [ 2, 3, 4 ]
    |> Stack.map (\{ index } n -> index * n)
--> topDown 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 (topDown)


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


topDown 4 [ 5, 6 ]
    |> Stack.and (topDown 1 [ 2, 3 ])
    |> Stack.map (\_ ( n0, n1 ) -> n0 + n1)
--> topDown 5 [ 7, 9 ]
(top -> topMapped)
-> Emptiable (StackTopBelow top belowElement) possiblyOrNever
(StackTopBelow topMapped belowElement)
possiblyOrNever

Change the top element based on its current value. Its type is allowed to change

import Stack exposing (topDown, topMap)


topDown 1 [ 4, 9 ] |> topMap negate
--> topDown -1 [ 4, 9 ]
({ index : Int } -> belowElement -> belowElementMapped)
-> Emptiable (StackTopBelow top belowElement) possiblyOrNever
(StackTopBelow top belowElementMapped)
possiblyOrNever

Change every element below its top based on their { index } in the whole stack and their current value. Their type is allowed to change

import Stack exposing (topDown, belowTopMap)


topDown 1 [ 4, 9 ]
    |> belowTopMap (\_ -> negate)
--> topDown 1 [ -4, -9 ]
accumulationValue
-> Direction
-> (element -> accumulationValue -> accumulationValue)
-> Emptiable (Stacked element) possiblyOrNever_
-> accumulationValue

Reduce in a direction

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


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


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

Be aware:

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

Fold from the top as the initial accumulation value

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


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

Be aware:

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

∑ Total every element number

import Emptiable


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


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


Emptiable.empty |> Stack.sum
--> 0
Emptiable (StackTopBelow top belowElement) Never
-> ( top, List belowElement )

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

import Stack exposing (topDown, toTopDown)


topDown "hi" [ "there", "👋" ]
    |> toTopDown
--> ( "hi", [ "there", "👋" ] )

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

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

Convert to a List

import Stack exposing (topDown)


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

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

toText : Emptiable (Stacked Char) possiblyOrNever_ -> String

Convert to a String

import Stack exposing (topDown)


topDown 'H' [ 'i' ] |> Stack.toText
--> "Hi"

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