mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-19 16:57:40 +03:00
Make DA.List.Total return Optional instead (#11878)
* Make DA.List.Total return Optional instead. Instead of using ActionFail or CanAbort, return an Optional. The library user can then convert this into the appropriate error if they wish. This PR also removes DA.Optional.Total (and the deprecated DA.Maybe.Total) for having questionable utility. changelog_begin - [Daml Standard Library] DA.List.Total functions now return Optional instead of being polymorphic in the return type. DA.Optional.Total has been removed. changelog_end * update Examples.daml
This commit is contained in:
parent
df373466dc
commit
0852c8f6fa
@ -23,66 +23,86 @@ import DA.List hiding (foldBalanced1, head, tail, init, last, foldl1, foldr1,
|
||||
|
||||
import qualified DA.List
|
||||
|
||||
head : ActionFail m => [a] -> m a
|
||||
head (x::_) = pure x
|
||||
head [] = fail "head: empty list"
|
||||
-- | Return the first element of a list. Return `None` if list is empty.
|
||||
head : [a] -> Optional a
|
||||
head = \case
|
||||
(x :: _) -> Some x
|
||||
[] -> None
|
||||
|
||||
tail : ActionFail m => [a] -> m [a]
|
||||
tail (_::xs) = pure xs
|
||||
tail [] = fail "tail: empty list"
|
||||
-- | Return all but the first element of a list. Return `None` if list is empty.
|
||||
tail : [a] -> Optional [a]
|
||||
tail = \case
|
||||
(_ :: xs) -> Some xs
|
||||
[] -> None
|
||||
|
||||
last : ActionFail m => [a] -> m a
|
||||
-- | Extract the last element of a list. Returns `None` if list is empty.
|
||||
last : [a] -> Optional a
|
||||
last = foldl1 (flip const)
|
||||
|
||||
init : ActionFail m => [a] -> m [a]
|
||||
init [_] = pure []
|
||||
init (x::xs) = do i <- init xs; pure (x :: i)
|
||||
init [] = fail "init: empty list"
|
||||
-- | Return all the elements of a list except the last one. Returns `None` if list is empty.
|
||||
init : [a] -> Optional [a]
|
||||
init = \case
|
||||
[] -> None
|
||||
[_] -> Some []
|
||||
(x :: xs) -> do
|
||||
xs' <- init xs
|
||||
Some (x :: xs')
|
||||
|
||||
infixl 9 !!
|
||||
(!!) : ActionFail m => [a] -> Int -> m a
|
||||
_ !! i | i < 0 = fail "(!!): negative index"
|
||||
[] !! _ = fail "(!!): index too large"
|
||||
(x::_) !! 0 = pure x
|
||||
-- | Return the nth element of a list. Return `None` if index is out of bounds.
|
||||
(!!) : [a] -> Int -> Optional a
|
||||
_ !! i | i < 0 = None
|
||||
[] !! _ = None
|
||||
(x::_) !! 0 = Some x
|
||||
(_::xs) !! i = xs !! (i-1)
|
||||
|
||||
foldl1 : ActionFail m => (a -> a -> a) -> [a] -> m a
|
||||
foldl1 f (x::xs) = pure (foldl f x xs)
|
||||
foldl1 _ [] = fail "foldl1: empty list"
|
||||
-- | Fold left starting with the head of the list.
|
||||
-- For example, `foldl1 f [a,b,c] = f (f a b) c`.
|
||||
-- Return `None` if list is empty.
|
||||
foldl1 : (a -> a -> a) -> [a] -> Optional a
|
||||
foldl1 f (x::xs) = Some (foldl f x xs)
|
||||
foldl1 _ [] = None
|
||||
|
||||
foldr1 : ActionFail m => (a -> a -> a) -> [a] -> m a
|
||||
foldr1 f [] = fail "foldr1: empty list"
|
||||
-- | Fold right starting with the last element of the list.
|
||||
-- For example, `foldr1 f [a,b,c] = f a (f b c)`
|
||||
foldr1 : (a -> a -> a) -> [a] -> Optional a
|
||||
foldr1 f [] = None
|
||||
foldr1 f xs = foldl1 (flip f) (reverse xs)
|
||||
|
||||
foldBalanced1 : ActionFail m => (a -> a -> a) -> [a] -> m a
|
||||
foldBalanced1 _ [] = fail "foldBalanced1: empty list"
|
||||
foldBalanced1 _ [x] = pure x
|
||||
foldBalanced1 f xs = foldBalanced1 f (combinePairs f xs)
|
||||
-- | Fold a non-empty list in a balanced way. Balanced means that each
|
||||
-- element has approximately the same depth in the operator
|
||||
-- tree. Approximately the same depth means that the difference
|
||||
-- between maximum and minimum depth is at most 1. The accumulation
|
||||
-- operation must be associative and commutative in order to get the
|
||||
-- same result as `foldl1` or `foldr1`.
|
||||
--
|
||||
-- Return `None` if list is empty.
|
||||
foldBalanced1 : (a -> a -> a) -> [a] -> Optional a
|
||||
foldBalanced1 f [] = None
|
||||
foldBalanced1 f xs = Some (DA.List.foldBalanced1 f xs)
|
||||
|
||||
-- | `minimumBy f xs` returns the first element `x` of `xs` for which `f x y`
|
||||
-- is either `LT` or `EQ` for all other `y` in `xs`. The result is
|
||||
-- wrapped in a monadic context, with a failure if `xs` is empty.
|
||||
minimumBy : (ActionFail m) => (a -> a -> Ordering) -> [a] -> m a
|
||||
minimumBy _ [] = fail "minimumBy: empty list"
|
||||
minimumBy f xs = pure $ DA.List.minimumBy f xs
|
||||
-- | Return the least element of a list according to the given comparison function.
|
||||
-- Return `None` if list is empty.
|
||||
minimumBy : (a -> a -> Ordering) -> [a] -> Optional a
|
||||
minimumBy _ [] = None
|
||||
minimumBy f xs = Some (DA.List.minimumBy f xs)
|
||||
|
||||
-- | `maximumBy f xs` returns the first element `x` of `xs` for which `f x y`
|
||||
-- is either `GT` or `EQ` for all other `y` in `xs`. The result is
|
||||
-- wrapped in a monadic context, with a failure if `xs` is empty.
|
||||
maximumBy : (ActionFail m) => (a -> a -> Ordering) -> [a] -> m a
|
||||
maximumBy _ [] = fail "maximumBy: empty list"
|
||||
maximumBy f xs = pure $ DA.List.maximumBy f xs
|
||||
-- | Return the greatest element of a list according to the given comparison function.
|
||||
-- Return `None` if list is empty.
|
||||
maximumBy : (a -> a -> Ordering) -> [a] -> Optional a
|
||||
maximumBy _ [] = None
|
||||
maximumBy f xs = Some (DA.List.maximumBy f xs)
|
||||
|
||||
-- | `minimumOn f xs` returns the first element `x` of `xs` for which `f x`
|
||||
-- is smaller than or equal to any other `f y` for `y` in `xs`. The result is
|
||||
-- wrapped in a monadic context, with a failure if `xs` is empty.
|
||||
minimumOn : (ActionFail m, Ord k) => (a -> k) -> [a] -> m a
|
||||
minimumOn _ [] = fail "minimumOn: empty list"
|
||||
minimumOn f xs = pure $ DA.List.minimumOn f xs
|
||||
-- | Return the least element of a list when comparing by a key function.
|
||||
-- For example `minimumOn (\(x,y) -> x + y) [(1,2), (2,0)] == Some (2,0)`.
|
||||
-- Return `None` if list is empty.
|
||||
minimumOn : (Ord k) => (a -> k) -> [a] -> Optional a
|
||||
minimumOn _ [] = None
|
||||
minimumOn f xs = Some (DA.List.minimumOn f xs)
|
||||
|
||||
-- | `maximumOn f xs` returns the first element `x` of `xs` for which `f x`
|
||||
-- is greater than or equal to any other `f y` for `y` in `xs`. The result is
|
||||
-- wrapped in a monadic context, with a failure if `xs` is empty.
|
||||
maximumOn : (ActionFail m, Ord k) => (a -> k) -> [a] -> m a
|
||||
maximumOn _ [] = fail "maximumOn: empty list"
|
||||
maximumOn f xs = pure $ DA.List.maximumOn f xs
|
||||
-- | Return the greatest element of a list when comparing by a key function.
|
||||
-- For example `maximumOn (\(x,y) -> x + y) [(1,2), (2,0)] == Some (1,2)`.
|
||||
-- Return `None` if list is empty.
|
||||
maximumOn : (Ord k) => (a -> k) -> [a] -> Optional a
|
||||
maximumOn _ [] = None
|
||||
maximumOn f xs = Some (DA.List.maximumOn f xs)
|
||||
|
@ -1,20 +0,0 @@
|
||||
-- Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
-- SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
-- | HIDE Hidden because deprecated.
|
||||
module DA.Maybe.Total
|
||||
( module DA.Maybe
|
||||
, module DA.Maybe.Total
|
||||
)
|
||||
where
|
||||
|
||||
import DA.Maybe hiding (fromJust, fromJustNote)
|
||||
import DA.Optional.Total
|
||||
|
||||
{-# DEPRECATED fromJust "Daml 1.2 compatibility helper, use 'fromSome' from 'DA.Optional.Total' instead of 'fromJust'" #-}
|
||||
fromJust : ActionFail m => Optional a -> m a
|
||||
fromJust = fromSome
|
||||
|
||||
{-# DEPRECATED fromJustNote "Daml 1.2 compatibility helper, use 'fromSomeNote' from 'DA.Optional.Total' instead of 'fromJustNote'" #-}
|
||||
fromJustNote : ActionFail m => Text -> Optional a -> m a
|
||||
fromJustNote = fromSomeNote
|
@ -1,17 +0,0 @@
|
||||
-- Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
-- SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
module DA.Optional.Total
|
||||
( module DA.Optional
|
||||
, module DA.Optional.Total
|
||||
)
|
||||
where
|
||||
|
||||
import DA.Optional hiding (fromSome, fromSomeNote)
|
||||
|
||||
fromSome : ActionFail m => Optional a -> m a
|
||||
fromSome = fromSomeNote "fromSome: None"
|
||||
|
||||
fromSomeNote : ActionFail m => Text -> Optional a -> m a
|
||||
fromSomeNote _ (Some x) = pure x
|
||||
fromSomeNote n None = fail n
|
@ -37,12 +37,10 @@ import DA.List.BuiltinOrder
|
||||
import DA.Logic
|
||||
import DA.Map
|
||||
import DA.Math
|
||||
import DA.Maybe.Total
|
||||
import DA.Maybe
|
||||
import DA.Monoid
|
||||
import DA.NonEmpty
|
||||
import DA.Numeric
|
||||
import DA.Optional.Total
|
||||
import DA.Optional
|
||||
import DA.Random
|
||||
import DA.Record
|
||||
|
@ -40,6 +40,5 @@ import Optional()
|
||||
-- import NextSet()
|
||||
import List()
|
||||
import Either()
|
||||
import Optional_Total()
|
||||
import Tuple()
|
||||
import Self2()
|
||||
|
@ -6,46 +6,49 @@ module List_Total where
|
||||
import DA.List.Total
|
||||
import DA.Assert
|
||||
|
||||
intNil : [Int]
|
||||
intNil = []
|
||||
|
||||
testHead = scenario do
|
||||
Left "head: empty list" === head @(Either Text) @Int []
|
||||
None === head intNil
|
||||
Some 1 === head [1, 2, 3]
|
||||
|
||||
testTail = scenario do
|
||||
Left "tail: empty list" === tail @(Either Text) @Int []
|
||||
None === tail intNil
|
||||
Some [2, 3] === tail [1, 2, 3]
|
||||
|
||||
testInit = scenario do
|
||||
Left "init: empty list" === init @(Either Text) @Int []
|
||||
None === init intNil
|
||||
Some [1, 2] === init [1, 2, 3]
|
||||
|
||||
testDoubleBang = scenario do
|
||||
Left "(!!): index too large" === [1, 2, 3] !! 4
|
||||
None === [1, 2, 3] !! 4
|
||||
Some 2 === [1, 2, 3] !! 1
|
||||
|
||||
testFoldl1 = scenario do
|
||||
Left "foldl1: empty list" === foldl1 @(Either Text) @Int (-) []
|
||||
None === foldl1 (-) intNil
|
||||
Some (-4) === foldl1 (-) [1, 2, 3]
|
||||
|
||||
testFoldr1 = scenario do
|
||||
Left "foldr1: empty list" === foldr1 @(Either Text) @Int (-) []
|
||||
None === foldr1 (-) intNil
|
||||
Some 2 === foldr1 (-) [1, 2, 3]
|
||||
|
||||
testFoldBalanced1 = scenario do
|
||||
Left "foldBalanced1: empty list" === foldBalanced1 @(Either Text) @Int (+) []
|
||||
None === foldBalanced1 (+) intNil
|
||||
Some 6 === foldBalanced1 (+) [1, 2, 3]
|
||||
|
||||
testMinimumOn = scenario do
|
||||
Left "minimumOn: empty list" === minimumOn @(Either Text) @Int @Int negate []
|
||||
None === minimumOn negate intNil
|
||||
Some 3 === minimumOn negate [1, 2, 3]
|
||||
|
||||
testMaximumOn = scenario do
|
||||
Left "maximumOn: empty list" === maximumOn @(Either Text) @Int @Int negate []
|
||||
None === maximumOn negate intNil
|
||||
Some 1 === maximumOn negate [1, 2, 3]
|
||||
|
||||
testBy = scenario do
|
||||
Left "minimumBy: empty list" === minimumBy @(Either Text) @Int compare []
|
||||
Left "maximumBy: empty list" === maximumBy @(Either Text) @Int compare []
|
||||
let cmp = (\x y -> compare (fst x) (fst y))
|
||||
let ls = [(2, 3), (4, 1), (1, 4)]
|
||||
Right (1, 4) === minimumBy @(Either Text) cmp ls
|
||||
None === minimumBy @(Int,Int) cmp []
|
||||
None === maximumBy @(Int,Int) cmp []
|
||||
Some (1, 4) === minimumBy cmp ls
|
||||
Some (4, 1) === maximumBy cmp ls
|
||||
|
@ -1,16 +1,15 @@
|
||||
-- Copyright (c) 2020, Digital Asset (Switzerland) GmbH and/or its affiliates.
|
||||
-- All rights reserved.
|
||||
|
||||
-- @WARN range=15:12-15:17; Maybe
|
||||
-- @WARN range=18:3-18:8; maybe
|
||||
-- @WARN range=18:20-18:27; Nothing
|
||||
-- @WARN range=19:3-19:11; fromSome
|
||||
-- @WARN range=19:13-19:17; Just
|
||||
-- @WARN range=14:12-14:17; Maybe
|
||||
-- @WARN range=17:3-17:8; maybe
|
||||
-- @WARN range=17:20-17:27; Nothing
|
||||
-- @WARN range=18:3-18:11; fromSome
|
||||
-- @WARN range=18:13-18:17; Just
|
||||
|
||||
module MaybeCompat where
|
||||
import DA.Assert
|
||||
import DA.Maybe
|
||||
import DA.Maybe.Total () -- we want to make sure there are not warnings in this module
|
||||
|
||||
type Foo = Maybe Int
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
-- Copyright (c) 2020, Digital Asset (Switzerland) GmbH and/or its affiliates.
|
||||
-- All rights reserved.
|
||||
|
||||
|
||||
module Optional_Total where
|
||||
|
||||
import DA.Optional.Total
|
||||
import DA.Assert
|
||||
|
||||
testFromSome = scenario do
|
||||
v <- fromSome (Some "abc")
|
||||
v === "abc"
|
||||
(Right 42 : Either Text Int) === fromSome (Some 42)
|
||||
(Left "fromSome: None" : Either Text Int) === fromSome None
|
||||
|
||||
testFromSomeNote = scenario do
|
||||
v <- fromSomeNote "error" (Some "abc")
|
||||
v === "abc"
|
||||
(Right 42 : Either Text Int) === fromSomeNote "problem" (Some 42)
|
||||
(Left "problem" : Either Text Int) === fromSomeNote "problem" None
|
Loading…
Reference in New Issue
Block a user