Skip to content

Commit e4ed181

Browse files
committed
Add synonyms (:|), (<|) for NonEmpty. Reimplement show with synonym.
1 parent eb7b45b commit e4ed181

File tree

6 files changed

+78
-45
lines changed

6 files changed

+78
-45
lines changed

sdk/compiler/damlc/daml-preprocessor/src/DA/Daml/Preprocessor.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ preprocessorExceptions = Set.fromList $ map GHC.mkModuleName
8989

9090
-- This module needs to use the PatternSynonyms extension.
9191
, "DA.Maybe"
92+
, "DA.NonEmpty"
9293
]
9394

9495
-- Following daml-script modules import Internal for creating psuedo exceptions

sdk/compiler/damlc/daml-stdlib-src/DA/NonEmpty.daml

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
-- Copyright (c) 2025 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
22
-- SPDX-License-Identifier: Apache-2.0
33

4+
{-# LANGUAGE PatternSynonyms #-}
45

56
-- | Type and functions for non-empty lists. This module re-exports many functions with
67
-- the same name as prelude list functions, so it is expected to import the module qualified.
@@ -13,6 +14,8 @@
1314
-- ```
1415
module DA.NonEmpty
1516
( NonEmpty(..)
17+
, pattern (:|)
18+
, (<|)
1619
, cons
1720
, append
1821
, map
@@ -40,10 +43,20 @@ import DA.NonEmpty.Types
4043
import DA.Traversable qualified as T
4144
import DA.List qualified as L
4245
import DA.Action qualified as M
46+
import DA.Internal.Record qualified
47+
48+
infixr 5 :|
49+
infixr 5 <|
50+
51+
-- | Pattern synonym for constructing and matching non-empty lists.
52+
pattern (:|) : a -> [a] -> NonEmpty a
53+
pattern (:|) x xs = NonEmpty x xs
54+
{-# COMPLETE (:|) : NonEmpty #-}
4355

4456
deriving instance Eq a => Eq (NonEmpty a)
45-
deriving instance Show a => Show (NonEmpty a)
4657
deriving instance Ord a => Ord (NonEmpty a)
58+
instance Show a => Show (NonEmpty a) where
59+
show (x :| xs) = show x <> " :| " <> show xs
4760

4861
-- NonEmpty is defined in a stable LF package so we need to handwrite the {Get,Set}Field instances here.
4962

@@ -76,22 +89,26 @@ instance Action NonEmpty where
7689
ys' = xs >>= toList . f
7790

7891
instance F.Foldable NonEmpty where
79-
foldr f z ne = f ne.hd (P.foldr f z ne.tl)
92+
foldr f z (h :| t) = f h (P.foldr f z t)
8093

8194
instance T.Traversable NonEmpty where
82-
mapA f l = liftA2 NonEmpty (f l.hd) (T.mapA f l.tl)
95+
mapA f (h :| t) = liftA2 (:|) (f h) (T.mapA f t)
8396

8497
-- | Prepend an element to a non-empty list.
8598
cons : a -> NonEmpty a -> NonEmpty a
86-
cons a ne = NonEmpty a (ne.hd :: ne.tl)
99+
cons a (h :| t) = a :| h :: t
100+
101+
-- | Alias for `cons`.
102+
(<|) : a -> NonEmpty a -> NonEmpty a
103+
(<|) = cons
87104

88105
-- | Append or concatenate two non-empty lists.
89106
append : NonEmpty a -> NonEmpty a -> NonEmpty a
90-
append l r = NonEmpty l.hd (l.tl ++ toList r)
107+
append (h :| t) r = h :| t ++ toList r
91108

92109
-- | Apply a function over each element in the non-empty list.
93110
map : (a -> b) -> NonEmpty a -> NonEmpty b
94-
map f ne = NonEmpty (f ne.hd) (P.map f ne.tl)
111+
map f (h :| t) = f h :| P.map f t
95112

96113
-- | Turn a list into a non-empty list, if possible. Returns
97114
-- `None` if the input list is empty, and `Some` otherwise.
@@ -130,7 +147,7 @@ delete = deleteBy (==)
130147
-- | Apply a function repeatedly to pairs of elements from a non-empty list,
131148
-- from the left. For example, `foldl1 (+) (NonEmpty 1 [2,3,4]) = ((1 + 2) + 3) + 4`.
132149
foldl1 : (a -> a -> a) -> NonEmpty a -> a
133-
foldl1 f l = L.foldl f l.hd l.tl
150+
foldl1 f (h :| t) = L.foldl f h t
134151

135152
-- | Apply a function repeatedly to pairs of elements from a non-empty list,
136153
-- from the right. For example, `foldr1 (+) (NonEmpty 1 [2,3,4]) = 1 + (2 + (3 + 4))`.
@@ -149,7 +166,7 @@ foldrA f x xs = foldr (\ y acc -> do v <- acc; f y v) (pure x) xs
149166

150167
-- | The same as `foldr1` but running an action each time.
151168
foldr1A : Action m => (a -> a -> m a) -> NonEmpty a -> m a
152-
foldr1A f l = M.foldrA f l.hd l.tl
169+
foldr1A f (h :| t) = M.foldrA f h t
153170

154171
-- | Apply a function repeatedly to pairs of elements from a non-empty list,
155172
-- from the left, with a given initial value. For example,
@@ -163,7 +180,7 @@ foldlA f x xs = foldl (\ acc y -> do v <- acc; f v y) (pure x) xs
163180

164181
-- | The same as `foldl1` but running an action each time.
165182
foldl1A : Action m => (a -> a -> m a) -> NonEmpty a -> m a
166-
foldl1A f l = M.foldlA f l.hd l.tl
183+
foldl1A f (h :| t) = M.foldlA f h t
167184

168185
instance IsParties (NonEmpty Party) where
169186
toParties = toList

sdk/compiler/damlc/tests/daml-test-files/NonEmpty.daml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ testOrd = script do
2727

2828
testCons = script do
2929
cons "a" (NonEmpty "b" []) === NonEmpty "a" ["b"]
30+
cons 1 (NonEmpty 2 [3, 4]) === 1 <| 2 :| [3, 4]
3031

3132
testFind = script do
3233
find (== 1) (NonEmpty 0 []) === None
@@ -47,11 +48,14 @@ testDelete = script do
4748
delete 1 (NonEmpty 0 [2, 1]) === [0, 2]
4849
delete 1 (NonEmpty 0 [1, 2, 1]) === [0, 2, 1]
4950

50-
5151
testDeleteBy = script do
5252
deleteBy eq 1 (NonEmpty 0 []) === [0]
5353
deleteBy eq 1 (NonEmpty 1 []) === []
5454
deleteBy (/=) 1 (NonEmpty 0 [1]) === [1]
5555
where
5656
-- Get dlint to stop complaining.
5757
eq = (==)
58+
59+
testShow = script do
60+
show (NonEmpty 1 []) === "1 :| []"
61+
show (NonEmpty "a" ["b", "c"]) === "\"a\" :| [\"b\",\"c\"]"

0 commit comments

Comments
 (0)