lue-bird/elm-emptiness-typed/9.1.2

NOTE: the latest version is 9.2.1

Stack

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

type Stacked element
= TopBelow ( element, List element )

The representation of a non-empty stack on the Filled case. top, removeTop, 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, map)
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
    |> map (filled >> top)
--: Emptiable String Possibly

create

Emptiable.empty to create an Empty Possibly stack

one : element -> Emptiable (Stacked element) never_

A stack with just 1 single element

import Emptiable
import Stack exposing (onTopLay)


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

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

Stack.topBelow ":)" [ "wait", "a", "moment" ]
--> Stack.topBelow "wait" [ "a", "moment" ]
-->     |> onTopLay ":)"
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 attachd 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 attachd below

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


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


"hello" |> Stack.fromString
--> 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.fromString)
fuzz : Fuzzer element -> Fuzzer (Emptiable (Stacked element) Possibly)

Emptiable (Stacked ...) Possibly Fuzzer. Generates stacks of varying length <= 32

import Stack exposing (topBelow)
import Fuzz


Stack.fuzz (Fuzz.intRange 0 9)
    |> Fuzz.examples 3
--> [ topBelow 2 [ 2, 5, 3, 8, 9, 4, 1, 0, 6, 6, 4, 7, 2, 6, 5 ]
--> , topBelow 8 [ 8, 0, 9, 8, 1, 0, 4, 1, 4, 6, 3, 4 ]
--> , topBelow 9 [ 7, 1, 5, 8, 2, 8, 3, 7, 4, 7 ]
--> ]
--: List (Emptiable (Stacked Int) Possibly)
filledFuzz : Fuzzer element -> Fuzzer (Emptiable (Stacked element) never_)

Emptiable Stacked Never Fuzzer. Generates stacks of varying length <= 32

import Stack exposing (topBelow)
import Fuzz


Stack.filledFuzz (Fuzz.intRange 0 9)
    |> Fuzz.examples 3
--> [ topBelow 4 [ 2, 2, 5, 3, 8, 9, 4, 1, 0, 6, 6, 4, 7, 2, 6, 5 ]
--> , topBelow 3 [ 4, 4, 5, 1, 7, 4, 2, 5, 6, 9, 7, 0, 1, 4, 1, 3, 2, 9, 6, 9, 0, 8, 3, 3, 3, 1, 5, 4, 9, 5, 2, 8 ]
--> , topBelow 5 [ 4, 9, 8, 9 ]
--> ]

scan

top : Emptiable (Stacked element) Never -> element

The first value

import Stack exposing (top, onTopLay)


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

How many element there are

import Stack exposing (onTopLay)


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

O(n) like List.length

removeTop 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.one 1
Emptiable (Stacked element) Never
-> Emptiable (Stacked element) Possibly

Everything after the first element

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


Stack.one 2
    |> Stack.onTopLay 3
    |> Stack.attach Down (topBelow 1 [ 0 ])
    |> Stack.removeTop
--> 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

attaching

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

Glue the elements of a given stack to the end in a given direction of the stack

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


topBelow 1 [ 2 ]
    |> Stack.attach Down (topBelow -1 [ 0 ])
--> topBelow -1 [ 0, 1, 2 ]


topBelow 1 [ 2 ]
    |> Stack.attach Down ([ -1, 0 ] |> Stack.fromList)
--> topBelow -1 [ 0, 1, 2 ]

Be aware:

  • Down = indexes decreasing, not: from the top lower
  • Up = indexes increasing, not: from the bottom up

Compared to attachAdapt

  • attach takes on the possiblyOrNever type of the incoming attachment Stack
  • attachAdapt takes on the possiblyOrNever type of the argument
Direction
-> Emptiable (Stacked element) possiblyOrNever
-> Emptiable (Stacked element) possiblyOrNeverIn_
-> Emptiable (Stacked element) possiblyOrNever

Glue the elements of a given stack to the end in a given direction of the stack, taking on the emptiness knowledge of the given stack

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


Emptiable.empty
    |> Stack.attachAdapt Down (topBelow 1 [ 2 ])
    |>  Stack.attachAdapt Down (topBelow -2 [ -1, 0 ])
--> topBelow -2 [ -1, 0, 1, 2 ]

Be aware:

  • Down = indexes decreasing, not: from the top lower
  • Up = indexes increasing, not: from the bottom up

Compared to attach

  • attach takes on the possiblyOrNever type of the incoming attachment Stack
  • attachAdapt 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 filled stack, all stacks must be filled

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

Usually used to convert to a different non-empty structure

-- module SetFilled exposing (SetFilled, fromStack, insert, one)


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


fromStack : Emptiable (Stacked comparable) Never -> SetFilled comparable
fromStack =
    Stack.foldFromOne one Up insert


type alias SetFilled comparable =
    { anElement : comparable
    , otherElements : Set comparable
    }


one : comparable -> SetFilled comparable
one onlyElement =
    { anElement = onlyElement, otherElements = Set.empty }


insert : comparable -> (SetFilled comparable -> SetFilled comparable)
insert toInsert =
    \setFilled ->
        if toInsert == setFilled.anElement then
            setFilled
        else
            -- new element
            { setFilled
                | otherElements =
                    setFilled.otherElements |> Set.insert toInsert
            }


topBelow 3 [ 4, 5, 4, 3 ]
    |> fromStack
--> { anElement = 3, otherElements = Set.fromList [ 5, 4 ] }

(Know there's is something better than SetFilled: KeySet)

fold is a simple version that folds directly from the start element:

Stack.fold =
    Stack.foldFromOne 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

To fold into a different non-empty structure → Stack.foldFromOne

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.removeTop

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