Import NonEmpty/

This commit is contained in:
Charlotte 🦝 Delenk 2022-09-01 20:25:02 +01:00
parent 182738f0fb
commit 8fc7b60c0e
Signed by: darkkirb
GPG key ID: AB2BD8DAF2E37122
20 changed files with 528 additions and 0 deletions

9
NonEmpty/Type.dhall Normal file
View file

@ -0,0 +1,9 @@
{-|
A `NonEmpty` list has at least one element and supports many of the same
operations as `List`s
-}
let NonEmpty
: Type → Type
= λ(a : Type) → { head : a, tail : List a }
in NonEmpty

28
NonEmpty/all.dhall Normal file
View file

@ -0,0 +1,28 @@
{-|
Returns `True` if the supplied function returns `True` for all elements in the
`NonEmpty` list
-}
let NonEmpty = ./Type.dhall
let NonEmpty/toList = ./toList.dhall
let all
: ∀(a : Type) → (a → Bool) → NonEmpty a → Bool
= λ(a : Type) →
λ(f : a → Bool) →
λ(xs : NonEmpty a) →
List/fold
a
(NonEmpty/toList a xs)
Bool
(λ(x : a) → λ(r : Bool) → f x && r)
True
let example0 =
assert : all Natural Natural/even { head = 2, tail = [ 3, 5 ] } ≡ False
let example1 =
assert
: all Natural Natural/even { head = 2, tail = [] : List Natural } ≡ True
in all

28
NonEmpty/any.dhall Normal file
View file

@ -0,0 +1,28 @@
{-|
Returns `True` if the supplied function returns `True` for any element in the
`NonEmpty` list
-}
let NonEmpty = ./Type.dhall
let NonEmpty/toList = ./toList.dhall
let any
: ∀(a : Type) → (a → Bool) → NonEmpty a → Bool
= λ(a : Type) →
λ(f : a → Bool) →
λ(xs : NonEmpty a) →
List/fold
a
(NonEmpty/toList a xs)
Bool
(λ(x : a) → λ(r : Bool) → f x || r)
False
let example0 =
assert : any Natural Natural/even { head = 2, tail = [ 3, 5 ] } ≡ True
let example1 =
assert
: any Natural Natural/even { head = 3, tail = [] : List Natural } ≡ False
in any

52
NonEmpty/concat.dhall Normal file
View file

@ -0,0 +1,52 @@
{-|
Concatenate a `NonEmpty` list of `NonEmpty` lists into a single `NonEmpty`
list
-}
let NonEmpty = ./Type.dhall
let NonEmpty/toList = ./toList.dhall
let List/concatMap = ../List/concatMap.dhall
let concat
: ∀(a : Type) → NonEmpty (NonEmpty a) → NonEmpty a
= λ(a : Type) →
λ(xss : NonEmpty (NonEmpty a)) →
{ head = xss.head.head
, tail =
xss.head.tail
# List/concatMap (NonEmpty a) a (NonEmpty/toList a) xss.tail
}
let example0 =
assert
: concat
Natural
{ head = { head = 0, tail = [ 1, 2 ] }
, tail =
[ { head = 3, tail = [ 4 ] }, { head = 5, tail = [ 6, 7, 8 ] } ]
}
≡ { head = 0, tail = [ 1, 2, 3, 4, 5, 6, 7, 8 ] }
let example1 =
assert
: concat
Natural
{ head = { head = 0, tail = [] : List Natural }
, tail =
[ { head = 1, tail = [] : List Natural }
, { head = 2, tail = [] : List Natural }
]
}
≡ { head = 0, tail = [ 1, 2 ] : List Natural }
let example2 =
assert
: concat
Natural
{ head = { head = 0, tail = [] : List Natural }
, tail = [] : List (NonEmpty Natural)
}
≡ { head = 0, tail = [] : List Natural }
in concat

47
NonEmpty/concatMap.dhall Normal file
View file

@ -0,0 +1,47 @@
{-|
Transform a `NonEmpty` list by applying a function to each element and
flattening the results
-}
let NonEmpty = ./Type.dhall
let NonEmpty/toList = ./toList.dhall
let List/concatMap = ../List/concatMap.dhall
let concatMap
: ∀(a : Type) → ∀(b : Type) → (a → NonEmpty b) → NonEmpty a → NonEmpty b
= λ(a : Type) →
λ(b : Type) →
λ(f : a → NonEmpty b) →
λ(xs : NonEmpty a) →
let ys = f xs.head
in { head = ys.head
, tail =
ys.tail
# List/concatMap
a
b
(λ(x : a) → NonEmpty/toList b (f x))
xs.tail
}
let example0 =
assert
: concatMap
Natural
Natural
(λ(n : Natural) → { head = n, tail = [ n ] })
{ head = 2, tail = [ 3, 5 ] }
≡ { head = 2, tail = [ 2, 3, 3, 5, 5 ] }
let example1 =
assert
: concatMap
Natural
Natural
(λ(n : Natural) → { head = n, tail = [ n ] })
{ head = 2, tail = [] : List Natural }
≡ { head = 2, tail = [ 2 ] }
in concatMap

10
NonEmpty/head.dhall Normal file
View file

@ -0,0 +1,10 @@
--| Retrieve the first element of the `NonEmpty` list
let NonEmpty = ./Type.dhall
let head
: ∀(a : Type) → NonEmpty a → a
= λ(a : Type) → λ(xs : NonEmpty a) → xs.head
let example = assert : head Natural { head = 0, tail = [ 1, 2 ] } ≡ 0
in head

27
NonEmpty/index.dhall Normal file
View file

@ -0,0 +1,27 @@
--| Retrieve an element from a `NonEmpty` list using its 0-based index
let NonEmpty = ./Type.dhall
let List/index = ../List/index.dhall
let index
: Natural → ∀(a : Type) → NonEmpty a → Optional a
= λ(n : Natural) →
λ(a : Type) →
λ(xs : NonEmpty a) →
if Natural/isZero n
then Some xs.head
else List/index (Natural/subtract 1 n) a xs.tail
let property =
λ(n : Natural) →
λ(a : Type) →
λ(xs : NonEmpty a) →
assert : index 0 a xs ≡ Some xs.head
let example0 = assert : index 1 Natural { head = 2, tail = [ 3, 5 ] } ≡ Some 3
let example1 =
assert
: index 1 Natural { head = 2, tail = [] : List Natural } ≡ None Natural
in index

35
NonEmpty/indexed.dhall Normal file
View file

@ -0,0 +1,35 @@
--| Tag each element of the `NonEmpty` list with its index
let NonEmpty = ./Type.dhall
let List/map = ../List/map.dhall
let indexed
: ∀(a : Type) → NonEmpty a → NonEmpty { index : Natural, value : a }
= λ(a : Type) →
λ(xs : NonEmpty a) →
{ head = { index = 0, value = xs.head }
, tail =
List/map
{ index : Natural, value : a }
{ index : Natural, value : a }
( λ(ix : { index : Natural, value : a }) →
{ index = ix.index + 1, value = ix.value }
)
(List/indexed a xs.tail)
}
let example0 =
assert
: indexed Bool { head = True, tail = [ False, True ] }
≡ { head = { index = 0, value = True }
, tail = [ { index = 1, value = False }, { index = 2, value = True } ]
}
let example1 =
assert
: indexed Bool { head = True, tail = [] : List Bool }
≡ { head = { index = 0, value = True }
, tail = [] : List { index : Natural, value : Bool }
}
in indexed

12
NonEmpty/last.dhall Normal file
View file

@ -0,0 +1,12 @@
λ(nix : ../NixPrelude.dhall) →
let NonEmpty = ./Type.dhall
let Optional/default = ../Optional/default.dhall nix
let last
: ∀(a : Type) → NonEmpty a → a
= λ(a : Type) →
λ(xs : NonEmpty a) →
Optional/default a xs.head (List/last a xs.tail)
in last

13
NonEmpty/length.dhall Normal file
View file

@ -0,0 +1,13 @@
--| Returns the number of elements in a `NonEmpty` list
let NonEmpty = ./Type.dhall
let length
: ∀(a : Type) → NonEmpty a → Natural
= λ(a : Type) → λ(xs : NonEmpty a) → List/length a xs.tail + 1
let example0 = assert : length Natural { head = 0, tail = [ 1, 2 ] } ≡ 3
let example1 =
assert : length Natural { head = 0, tail = [] : List Natural } ≡ 1
in length

15
NonEmpty/make.dhall Normal file
View file

@ -0,0 +1,15 @@
{-|
Create a `NonEmpty` list using a function instead of a record
This might come in handy if you want to decouple the `NonEmpty` list
construction from the specific names of the fields.
-}
let NonEmpty = ./Type.dhall
let make
: ∀(a : Type) → ∀(head : a) → ∀(tail : List a) → NonEmpty a
= λ(a : Type) → λ(head : a) → λ(tail : List a) → { head, tail }
let example = assert : make Natural 1 [ 2, 3 ] ≡ { head = 1, tail = [ 2, 3 ] }
in make

24
NonEmpty/map.dhall Normal file
View file

@ -0,0 +1,24 @@
--| Transform a `NonEmpty` list by applying a function to each element
let NonEmpty = ./Type.dhall
let List/map = ../List/map.dhall
let map
: ∀(a : Type) → ∀(b : Type) → (a → b) → NonEmpty a → NonEmpty b
= λ(a : Type) →
λ(b : Type) →
λ(f : a → b) →
λ(xs : NonEmpty a) →
{ head = f xs.head, tail = List/map a b f xs.tail }
let example0 =
assert
: map Natural Bool Natural/even { head = 2, tail = [ 3, 5 ] }
≡ { head = True, tail = [ False, False ] }
let example1 =
assert
: map Natural Bool Natural/even { head = 2, tail = [] : List Natural }
≡ { head = True, tail = [] : List Bool }
in map

20
NonEmpty/package.dhall Normal file
View file

@ -0,0 +1,20 @@
λ(nix : ../NixPrelude.dhall) →
{ Type = ./Type.dhall
, all = ./all.dhall
, any = ./any.dhall
, concat = ./concat.dhall
, concatMap = ./concatMap.dhall
, head = ./head.dhall
, index = ./index.dhall
, indexed = ./indexed.dhall
, last = ./last.dhall nix
, length = ./length.dhall
, make = ./make.dhall
, map = ./map.dhall
, reverse = ./reverse.dhall nix
, shifted = ./shifted.dhall
, singleton = ./singleton.dhall
, toList = ./toList.dhall
, unzip = ./unzip.dhall
, zip = ./zip.dhall nix
}

21
NonEmpty/reverse.dhall Normal file
View file

@ -0,0 +1,21 @@
λ(nix : ../NixPrelude.dhall) →
let NonEmpty = ./Type.dhall
let List/drop = ../List/drop.dhall
let Optional/fold = ../Optional/fold.dhall nix
let reverse
: ∀(a : Type) → NonEmpty a → NonEmpty a
= λ(a : Type) →
λ(xs : NonEmpty a) →
let ys = List/reverse a xs.tail
in Optional/fold
a
(List/head a ys)
(NonEmpty a)
(λ(y : a) → { head = y, tail = List/drop 1 a ys # [ xs.head ] })
{ head = xs.head, tail = [] : List a }
in reverse

89
NonEmpty/shifted.dhall Normal file
View file

@ -0,0 +1,89 @@
{-|
Combine a `NonEmpty` list of `NonEmpty` lists, offsetting the `index` of each
element by the number of elements in preceding lists
-}
let NonEmpty = ./Type.dhall
let NonEmpty/toList = ./toList.dhall
let List/map = ../List/map.dhall
let List/shifted = ../List/shifted.dhall
let shifted
: ∀(a : Type) →
NonEmpty (NonEmpty { index : Natural, value : a }) →
NonEmpty { index : Natural, value : a }
= λ(a : Type) →
λ(kvss : NonEmpty (NonEmpty { index : Natural, value : a })) →
{ head = kvss.head.head
, tail =
List/shifted
a
( [ kvss.head.tail ]
# List/map
(NonEmpty { index : Natural, value : a })
(List { index : Natural, value : a })
( λ(kvs : NonEmpty { index : Natural, value : a }) →
List/map
{ index : Natural, value : a }
{ index : Natural, value : a }
( λ(kv : { index : Natural, value : a }) →
{ index = kv.index + 1, value = kv.value }
)
(NonEmpty/toList { index : Natural, value : a } kvs)
)
kvss.tail
)
}
let example0 =
assert
: shifted
Bool
{ head =
{ head = { index = 0, value = True }
, tail =
[ { index = 1, value = True }, { index = 2, value = True } ]
}
, tail =
[ { head = { index = 0, value = False }
, tail = [ { index = 1, value = False } ]
}
, { head = { index = 0, value = True }
, tail =
[ { index = 1, value = True }
, { index = 2, value = True }
, { index = 3, value = True }
]
}
]
}
≡ { head = { index = 0, value = True }
, tail =
[ { index = 1, value = True }
, { index = 2, value = True }
, { index = 3, value = False }
, { index = 4, value = False }
, { index = 5, value = True }
, { index = 6, value = True }
, { index = 7, value = True }
, { index = 8, value = True }
]
}
let example1 =
assert
: shifted
Bool
{ head =
{ head = { index = 0, value = True }
, tail = [] : List { index : Natural, value : Bool }
}
, tail = [] : List (NonEmpty { index : Natural, value : Bool })
}
≡ { head = { index = 0, value = True }
, tail = [] : List { index : Natural, value : Bool }
}
in shifted

11
NonEmpty/singleton.dhall Normal file
View file

@ -0,0 +1,11 @@
--| Create a `NonEmpty` list with just one element
let NonEmpty = ./Type.dhall
let singleton
: ∀(a : Type) → a → NonEmpty a
= λ(a : Type) → λ(x : a) → { head = x, tail = [] : List a }
let example =
assert : singleton Natural 2 ≡ { head = 2, tail = [] : List Natural }
in singleton

14
NonEmpty/toList.dhall Normal file
View file

@ -0,0 +1,14 @@
--| Convert a `NonEmpty` list into the equivalent `List`
let NonEmpty = ./Type.dhall
let toList
: ∀(a : Type) → NonEmpty a → List a
= λ(a : Type) → λ(xs : NonEmpty a) → [ xs.head ] # xs.tail
let example0 =
assert : toList Natural { head = 2, tail = [ 3, 5 ] } ≡ [ 2, 3, 5 ]
let example1 =
assert : toList Natural { head = 2, tail = [] : List Natural } ≡ [ 2 ]
in toList

52
NonEmpty/unzip.dhall Normal file
View file

@ -0,0 +1,52 @@
--| Unzip a `NonEmpty` list into two separate `NonEmpty` lists
let NonEmpty = ./Type.dhall
let NonEmpty/map = ./map.dhall
let unzip
: ∀(a : Type) →
∀(b : Type) →
NonEmpty { _1 : a, _2 : b } →
{ _1 : NonEmpty a, _2 : NonEmpty b }
= λ(a : Type) →
λ(b : Type) →
λ(xs : NonEmpty { _1 : a, _2 : b }) →
{ _1 =
NonEmpty/map
{ _1 : a, _2 : b }
a
(λ(x : { _1 : a, _2 : b }) → x._1)
xs
, _2 =
NonEmpty/map
{ _1 : a, _2 : b }
b
(λ(x : { _1 : a, _2 : b }) → x._2)
xs
}
let example0 =
assert
: unzip
Text
Bool
{ head = { _1 = "ABC", _2 = True }
, tail = [ { _1 = "DEF", _2 = False }, { _1 = "GHI", _2 = True } ]
}
≡ { _1 = { head = "ABC", tail = [ "DEF", "GHI" ] }
, _2 = { head = True, tail = [ False, True ] }
}
let example1 =
assert
: unzip
Text
Bool
{ head = { _1 = "ABC", _2 = True }
, tail = [] : List { _1 : Text, _2 : Bool }
}
≡ { _1 = { head = "ABC", tail = [] : List Text }
, _2 = { head = True, tail = [] : List Bool }
}
in unzip

20
NonEmpty/zip.dhall Normal file
View file

@ -0,0 +1,20 @@
λ(nix : ../NixPrelude.dhall) →
let NonEmpty = ./Type.dhall
let List/zip = ../List/zip.dhall nix
let zip
: ∀(a : Type) →
NonEmpty a →
∀(b : Type) →
NonEmpty b →
NonEmpty { _1 : a, _2 : b }
= λ(a : Type) →
λ(xs : NonEmpty a) →
λ(b : Type) →
λ(ys : NonEmpty b) →
{ head = { _1 = xs.head, _2 = ys.head }
, tail = List/zip a xs.tail b ys.tail
}
in zip

View file

@ -9,6 +9,7 @@
, Map = ./Map/package.dhall nix
, Misc = ./Misc/package.dhall nix
, Monoid = ./Monoid.dhall
, NonNull = ./NonEmpty/package.dhall nix
, Natural = ./Natural/package.dhall nix
, Number = ./Number/package.dhall nix
, Path = ./Path/package.dhall nix