Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More NonEmpty functions #10930

Merged
merged 4 commits into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion compiler/damlc/daml-stdlib-src/DA/NonEmpty.daml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
-- ```
module DA.NonEmpty
( NonEmpty(..)
, cons
, append
, map
, nonEmpty
, singleton
, toList
, reverse
, find
, delete
, foldl1
, foldr1
, foldr
Expand All @@ -29,7 +32,7 @@ module DA.NonEmpty
, foldl1A
) where

import Prelude hiding (reverse, foldr, foldl, one, map)
import Prelude hiding (cons, reverse, find, foldr, foldl, one, map)
import Prelude qualified as P
import DA.Foldable qualified as F
import DA.NonEmpty.Types
Expand Down Expand Up @@ -73,6 +76,10 @@ instance F.Foldable NonEmpty where
instance T.Traversable NonEmpty where
mapA f l = liftA2 NonEmpty (f l.hd) (T.mapA f l.tl)

-- | Prepend an element to a non-empty list.
cons : a -> NonEmpty a -> NonEmpty a
cons a ne = NonEmpty a (ne.hd :: ne.tl)

-- | Append or concatenate two non-empty lists.
append : NonEmpty a -> NonEmpty a -> NonEmpty a
append l r = NonEmpty l.hd (l.tl ++ toList r)
Expand All @@ -99,6 +106,28 @@ toList (NonEmpty head tail) = head :: tail
reverse : NonEmpty a -> NonEmpty a
reverse l = let hd::tl = L.reverse $ toList l in NonEmpty with hd; tl

-- | Find an element in a non-empty list.
find : (a -> Bool) -> NonEmpty a -> Optional a
find p (NonEmpty head tail)
| p head = Some head
| otherwise = L.find p tail

-- | The 'deleteBy' function behaves like 'delete', but takes a
-- user-supplied equality predicate.
deleteBy : (a -> a -> Bool) -> a -> NonEmpty a -> [a]
deleteBy eq a n@(NonEmpty head [])
| head `eq` a = []
| otherwise = [head]
deleteBy eq a (NonEmpty head (t::ts))
| head `eq` a = t::ts
| t `eq` a = head::ts
| otherwise = head :: t :: L.deleteBy eq a ts

-- | Remove the first occurence of x from the non-empty list, potentially
-- removing all elements.
delete : Eq a => a -> NonEmpty a -> [a]
delete = deleteBy (==)

-- | Apply a function repeatedly to pairs of elements from a non-empty list,
-- from the left. For example, `foldl1 (+) (NonEmpty 1 [2,3,4]) = ((1 + 2) + 3) + 4`.
foldl1 : (a -> a -> a) -> NonEmpty a -> a
Expand Down
26 changes: 25 additions & 1 deletion compiler/damlc/tests/daml-test-files/NonEmpty.daml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

module NonEmpty where

import DA.NonEmpty
import Prelude hiding (cons, find)
import DA.Assert
import DA.NonEmpty

testApplicative = scenario do
let l = NonEmpty 1 [2, 3, 4]
Expand All @@ -22,3 +23,26 @@ testOrd = scenario do
compare (NonEmpty 1 []) (NonEmpty 1 [0]) === LT
compare (NonEmpty 1 [0]) (NonEmpty 1 [0]) === EQ
compare (NonEmpty 1 [0]) (NonEmpty 1 [1]) === LT

testCons = scenario do
cons "a" (NonEmpty "b" []) === NonEmpty "a" ["b"]

testFind = scenario do
find (== 1) (NonEmpty 0 []) === None
find (== 1) (NonEmpty 1 []) === Some 1
find (== 1) (NonEmpty 0 [1]) === Some 1
find (== 1) (NonEmpty 0 [0]) === None
find (== 1) (NonEmpty 0 [1, 2]) === Some 1
find (== 1) (NonEmpty 0 [2, 1]) === Some 1
find (== 1) (NonEmpty 0 [1, 2, 1]) === Some 1

testDelete = scenario do
delete 1 (NonEmpty 0 []) === [0]
delete 1 (NonEmpty 1 []) === []
delete 1 (NonEmpty 0 [1]) === [0]
delete 1 (NonEmpty 0 [0]) === [0, 0]
delete 1 (NonEmpty 1 [0]) === [0]
delete 1 (NonEmpty 0 [1, 2]) === [0, 2]
delete 1 (NonEmpty 0 [2, 1]) === [0, 2]
delete 1 (NonEmpty 0 [1, 2, 1]) === [0, 2, 1]