turboMaCk / lazy-tree-with-zipper / Lazy.LList

This module implements lazy construction of strict List. It is not Lazy List implementation and it has different characteristics. It's mostly intended for internal purposes of this library and is exposed just in case some additional user extensions will need it.

Types & Constructors


type alias LList a =
Lazy (List a)

LList uses lazy implementation and therefore can't be compared using ==

empty : LList a

Initialize empty LList.

toList empty
--> []

singleton : a -> LList a

Initialize singleton LList.

singleton "foo"
    |> toList
--> [ "foo" ]

llist : (a -> List b) -> a -> LList b

Init LList using constructor.

LList is initialized using a function from a -> List b. Evaluation of this function is lazy and happens in time when actual value is needed, not when constructor is called.

For instance you can use some List constructor:

llist (List.range 0) 5
    |> toList
--> [ 0, 1, 2, 3, 4, 5 ]

Or use any other function you needList:

llist (List.filter <| \a -> modBy 2 a == 0) (List.range 0 10)
    |> toList
--> [ 0, 2, 4, 6, 8, 10 ]

fromList : List a -> LList a

Construct LList from List.

fromList [ "foo", "bar", "baz" ]
    |> toList
--> [ "foo", "bar", "baz" ]

Operations

cons : a -> LList a -> LList a

Add element to LList.

empty
    |> cons "bar"
    |> cons "foo"
    |> toList
--> [ "foo", "bar" ]

This function is performed lazily.

append : LList a -> LList a -> LList a

Append LList to LList.

append (singleton "foo") (fromList [ "bar", "baz" ])
    |> toList
--> [ "foo", "bar", "baz" ]

This function is performed lazily.

Query

isEmpty : LList a -> Basics.Bool

Check if LList is empty.

isEmpty empty
--> True

isEmpty (singleton "foo")
--> False

llist (List.filter <| \a -> a > 10) [ 1, 2, 3 ]
    |> isEmpty
--> True

This function forces evaluation.

toList : LList a -> List a

Build List from LList.

toList empty
--> []

toList <| llist (List.range 0) 2
--> [ 0, 1, 2 ]

This function forces evaluation.

head : LList a -> Maybe a

Get the first element from LList.

head empty
--> Nothing

llist (List.range 0) 2
   |> head
--> Just 0

This function forces evaluation.

tail : LList a -> Maybe (LList a)

Get the first element from LList.

tail empty
--> Nothing

tail (singleton "foo")
    |> Maybe.map toList
--> Just []

llist (List.range 0) 2
    |> tail
    |> Maybe.map toList
--> Just [ 1, 2 ]

This function forces evaluation.

Transformations

map : (a -> b) -> LList a -> LList b

Map function over LList.

llist (List.range 0) 5
    |> map ((*) 2)
    |> toList
--> [ 0, 2, 4, 6, 8, 10 ]

This function is performed lazily.

map2 : (a -> b -> c) -> LList a -> LList b -> LList c

Map a functions over two LLists.

llist (List.range 0) 5
    |> map2 (+) (llist (List.range 0) 5)
    |> toList
--> [ 0, 2, 4, 6, 8, 10 ]

This function is performed lazily.

filter : (a -> Basics.Bool) -> LList a -> LList a

Filter LList.

(cons 1 <| cons 2 <| cons 3 empty)
    |> filter ((<) 1)
    |> toList
--> [ 2, 3 ]

This function is performed lazily.

filterMap : (a -> Maybe b) -> LList a -> LList b

Similar to List.filterMap but for LList.

(cons 1 <| cons 2 <| cons 3 empty)
    |> filterMap (\a -> if 1 < a then Just (2 * a) else Nothing)
    |> toList
--> [ 4, 6 ]

This function is performed lazily.

reverse : LList a -> LList a

Reverse LList.

fromList [ 1, 2, 3 ]
    |> reverse
    |> toList
--> [ 3, 2, 1 ]

This function is performed lazily.

sort : LList comparable -> LList comparable

Sort by for LList.

fromList [ 3, 1, 2 ]
    |> sort
    |> toList
--> [ 1, 2, 3 ]

This function is performed lazily.

sortBy : (a -> comparable) -> LList a -> LList a

Sort by for LList.

fromList [ 3, 1, 2 ]
    |> sortBy identity
    |> toList
--> [ 1, 2, 3 ]

fromList [ { val = "c"} , { val = "b"}, { val = "a"} ]
    |> sortBy .val
    |> toList
-->  [ { val = "a"}, { val = "b"}, { val = "c"} ]

This function is performed lazily.

sortWith : (a -> a -> Basics.Order) -> LList a -> LList a

Sort with for LList

flippedComparison : comparable -> comparable -> Order
flippedComparison a b =
    case Basics.compare a b of
        LT -> GT
        EQ -> EQ
        GT -> LT

llist (List.range 1) 5
    |> sortWith flippedComparison
    |> toList
--> [ 5, 4, 3, 2, 1 ]

This function is performed lazily.

stableSortWith : (a -> a -> Basics.Order) -> LList a -> LList a

Stable sort with for LList. The original order is guaranteed to be kept if the comparison returns EQ.

compareAge : { r | age : comparable } -> { r | age : comparable } -> Order
compareAge a b =
    Basics.compare a.age b.age

fromList [ { name = "Joe", age = 25 }, { name = "Sue", age = 25 }, { name = "Johann", age = 23 } ]
    |> stableSortWith compareAge
    |> toList
--> [ { name = "Johann", age = 23 }, { name = "Joe", age = 25 }, { name = "Sue", age = 25 } ]

This function is performed lazily.

foldr : (a -> b -> b) -> b -> LList a -> b

Same as List.foldr but for LLists.

llist (List.range 0) 5
    |> foldr (+) 0
--> 15

llist (List.range 0) 3
    |> foldr (::) []
--> [ 0, 1, 2, 3 ]

This function forces evaluation.

foldl : (a -> b -> b) -> b -> LList a -> b

Same as List.foldl but for LLists.

llist (List.range 0) 5
    |> foldl (+) 0
--> 15

llist (List.range 0) 3
    |> foldl (::) []
--> [ 3, 2, 1, 0 ]

This function forces evaluation.

concat : LList (LList a) -> LList a

Flatten LList.

fromList [ singleton "foo", cons "bar" <| singleton "baz" ]
   |> concat
   |> toList
--> [ "foo", "bar", "baz" ]

This function is performed lazily.

andThen : (a -> LList b) -> LList a -> LList b

Map LList construction over LList.

cons "foo" (cons "bar" <| singleton "baz")
    |> andThen (\a -> cons a <| singleton (a ++ " fighter" ))
    |> toList
--> [ "foo", "foo fighter", "bar", "bar fighter", "baz", "baz fighter" ]

This function is performed lazily.