📚 An emptiable or non-empty structure where
top
, removeTop
, onTopLay
are O(n)
The representation of a non-empty stack on the Filled
case.
top
, removeTop
, onTopLay
are O(n)
Emptiable
(StackFilled ...) Never
→ stack
is non-empty:
top : Emptiable (Stacked element) Never -> element
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
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 List
s 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 String
s 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 ]
--> ]
top : Emptiable (Stacked element) Basics.Never -> element
The first value
import Stack exposing (top, onTopLay)
Stack.one 3
|> onTopLay 2
|> top
--> 2
length : Emptiable (Stacked element_) possiblyOrNever_ -> Basics.Int
How many element there are
import Stack exposing (onTopLay)
Stack.one 3
|> onTopLay 2
|> Stack.length
--> 2
O(n)
like List.length
onTopLay : 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
removeTop : Emptiable (Stacked element) Basics.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
topAlter : (element -> element) -> Emptiable (Stacked element) possiblyOrNever -> Emptiable (Stacked element) possiblyOrNever
Change the first element based on its current value
import Stack
Stack.topBelow "Helpy IQ 4000 – the amazing vacuum cleaner"
[ "faster and more thorough than ever seen before!" ]
|> Stack.topAlter (\firstLine -> "Introducing: " ++ firstLine)
--> Stack.topBelow "Introducing: Helpy IQ 4000 – the amazing vacuum cleaner" [ "faster and more thorough than ever seen before!" ]
reverse : 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" ]
fills : Emptiable (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
attach : Linear.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
lowerUp
= indexes increasing, not: from the bottom upCompared to attachAdapt
attach
takes on the possiblyOrNever
type of the incoming attachment StackattachAdapt
takes on the possiblyOrNever
type of the argumentattachAdapt : Linear.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
lowerUp
= indexes increasing, not: from the bottom upCompared to attach
attach
takes on the possiblyOrNever
type of the incoming attachment StackattachAdapt
takes on the possiblyOrNever
type of the argumentflatten : Emptiable (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
map : ({ index : Basics.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 ]
foldFrom : accumulationValue -> Linear.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
lowerUp
= indexes increasing, not: from the bottom upfoldFromOne : (element -> accumulated) -> Linear.Direction -> (element -> accumulated -> accumulated) -> Emptiable (Stacked element) Basics.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 or operate on a different non-empty structure
stackFilledReverse =
Stack.foldFromOne Stack.one Up Stack.onTopLay
-- 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
lowerUp
= indexes increasing, not: from the bottom upfold : Linear.Direction -> (element -> element -> element) -> Emptiable (Stacked element) Basics.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
lowerUp
= indexes increasing, not: from the bottom upsum : 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) Basics.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