Copyright | (c) 2021-2024 Rudy Matela |
---|---|
License | 3-Clause BSD (see the file LICENSE) |
Maintainer | Rudy Matela <[email protected]> |
Safe Haskell | None |
Language | Haskell2010 |
Conjure.Utils
Description
Synopsis
- module Data.List
- module Data.Function
- module Data.Maybe
- module Data.Monoid
- data Solo a where
- uncurry :: (a -> b -> c) -> (a, b) -> c
- getSolo :: Solo a -> a
- fst :: (a, b) -> a
- snd :: (a, b) -> b
- curry :: ((a, b) -> c) -> a -> b -> c
- swap :: (a, b) -> (b, a)
- module Data.Typeable
- count :: (a -> Bool) -> [a] -> Int
- nubOn :: Eq b => (a -> b) -> [a] -> [a]
- nubSort :: Ord a => [a] -> [a]
- mzip :: Monoid a => [a] -> [a] -> [a]
- groupOn :: Eq b => (a -> b) -> [a] -> [[a]]
- idIO :: (a -> IO ()) -> a -> a
- mapHead :: (a -> a) -> [a] -> [a]
- sets :: [a] -> [[a]]
- headOr :: a -> [a] -> a
- allEqual :: Eq a => [a] -> Bool
- allEqualOn :: Eq b => (a -> b) -> [a] -> Bool
- allEqual2 :: Eq a => [a] -> Bool
- choices :: [a] -> [(a, [a])]
- choicesThat :: (a -> [a] -> Bool) -> [a] -> [(a, [a])]
- foldr0 :: (a -> a -> a) -> a -> [a] -> a
- indent :: String -> String
- indentBy :: Int -> String -> String
- classify :: Eq a => [a] -> [[a]]
- classifyBy :: (a -> a -> Bool) -> [a] -> [[a]]
- classifyOn :: Eq b => (a -> b) -> [a] -> [[a]]
- none :: (a -> Bool) -> [a] -> Bool
- updateAt :: Int -> (a -> a) -> [a] -> [a]
- first :: (a -> a') -> (a, b) -> (a', b)
- second :: (b -> b') -> (a, b) -> (a, b')
- both :: (a -> b) -> (a, a) -> (b, b)
- (+++) :: Ord a => [a] -> [a] -> [a]
- isSubsetOf :: Ord a => [a] -> [a] -> Bool
Documentation
module Data.List
module Data.Function
module Data.Maybe
module Data.Monoid
Solo
is the canonical lifted 1-tuple, just like (,)
is the canonical
lifted 2-tuple (pair) and (,,)
is the canonical lifted 3-tuple (triple).
The most important feature of Solo
is that it is possible to force its
"outside" (usually by pattern matching) without forcing its "inside",
because it is defined as a datatype rather than a newtype. One situation
where this can be useful is when writing a function to extract a value from
a data structure. Suppose you write an implementation of arrays and offer
only this function to index into them:
index :: Array a -> Int -> a
Now imagine that someone wants to extract a value from an array and store it in a lazy-valued finite map/dictionary:
insert "hello" (arr index
12) m
This can actually lead to a space leak. The value is not actually extracted from the array until that value (now buried in a map) is forced. That means the entire array may be kept live by just that value! Often, the solution is to use a strict map, or to force the value before storing it, but for some purposes that's undesirable.
One common solution is to include an indexing function that can produce its
result in an arbitrary Applicative
context:
indexA :: Applicative f => Array a -> Int -> f a
When using indexA
in a pure context, Solo
serves as a handy
Applicative
functor to hold the result. You could write a non-leaky
version of the above example thus:
case arr indexA
12 of
Solo a -> insert "hello" a m
While such simple extraction functions are the most common uses for unary tuples, they can also be useful for fine-grained control of strict-spined data structure traversals, and for unifying the implementations of lazy and strict mapping functions.
Instances
MonadFix Solo | Since: base-4.15 | ||||
Defined in Control.Monad.Fix | |||||
MonadZip Solo | Since: base-4.15.0.0 | ||||
Foldable Solo | Since: base-4.15 | ||||
Defined in Data.Foldable Methods fold :: Monoid m => Solo m -> m # foldMap :: Monoid m => (a -> m) -> Solo a -> m # foldMap' :: Monoid m => (a -> m) -> Solo a -> m # foldr :: (a -> b -> b) -> b -> Solo a -> b # foldr' :: (a -> b -> b) -> b -> Solo a -> b # foldl :: (b -> a -> b) -> b -> Solo a -> b # foldl' :: (b -> a -> b) -> b -> Solo a -> b # foldr1 :: (a -> a -> a) -> Solo a -> a # foldl1 :: (a -> a -> a) -> Solo a -> a # elem :: Eq a => a -> Solo a -> Bool # maximum :: Ord a => Solo a -> a # | |||||
Foldable1 Solo | Since: base-4.18.0.0 | ||||
Defined in Data.Foldable1 Methods fold1 :: Semigroup m => Solo m -> m # foldMap1 :: Semigroup m => (a -> m) -> Solo a -> m # foldMap1' :: Semigroup m => (a -> m) -> Solo a -> m # toNonEmpty :: Solo a -> NonEmpty a # maximum :: Ord a => Solo a -> a # minimum :: Ord a => Solo a -> a # foldrMap1 :: (a -> b) -> (a -> b -> b) -> Solo a -> b # foldlMap1' :: (a -> b) -> (b -> a -> b) -> Solo a -> b # foldlMap1 :: (a -> b) -> (b -> a -> b) -> Solo a -> b # foldrMap1' :: (a -> b) -> (a -> b -> b) -> Solo a -> b # | |||||
Eq1 Solo | Since: base-4.15 | ||||
Ord1 Solo | Since: base-4.15 | ||||
Defined in Data.Functor.Classes | |||||
Read1 Solo | Since: base-4.15 | ||||
Defined in Data.Functor.Classes | |||||
Show1 Solo | Since: base-4.15 | ||||
Traversable Solo | Since: base-4.15 | ||||
Applicative Solo | Since: base-4.15 | ||||
Functor Solo | Since: base-4.15 | ||||
Monad Solo | Since: base-4.15 | ||||
Generic1 Solo | |||||
Defined in GHC.Generics Associated Types
| |||||
Data a => Data (Solo a) | Since: base-4.15 | ||||
Defined in Data.Data Methods gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Solo a -> c (Solo a) # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Solo a) # toConstr :: Solo a -> Constr # dataTypeOf :: Solo a -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (Solo a)) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (Solo a)) # gmapT :: (forall b. Data b => b -> b) -> Solo a -> Solo a # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Solo a -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Solo a -> r # gmapQ :: (forall d. Data d => d -> u) -> Solo a -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Solo a -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Solo a -> m (Solo a) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Solo a -> m (Solo a) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Solo a -> m (Solo a) # | |||||
Monoid a => Monoid (Solo a) | Since: base-4.15 | ||||
Semigroup a => Semigroup (Solo a) | Since: base-4.15 | ||||
Bounded a => Bounded (Solo a) | |||||
Enum a => Enum (Solo a) | |||||
Defined in GHC.Enum | |||||
Generic (Solo a) | |||||
Defined in GHC.Generics Associated Types
| |||||
Ix a => Ix (Solo a) | |||||
Read a => Read (Solo a) | Since: base-4.15 | ||||
Show a => Show (Solo a) | Since: base-4.15 | ||||
Eq a => Eq (Solo a) | |||||
Ord a => Ord (Solo a) | |||||
type Rep1 Solo | Since: base-4.15 | ||||
Defined in GHC.Generics | |||||
type Rep (Solo a) | Since: base-4.15 | ||||
Defined in GHC.Generics |
uncurry :: (a -> b -> c) -> (a, b) -> c #
uncurry
converts a curried function to a function on pairs.
Examples
>>>
uncurry (+) (1,2)
3
>>>
uncurry ($) (show, 1)
"1"
>>>
map (uncurry max) [(1,2), (3,4), (6,8)]
[2,4,8]
Extract the value from a Solo
. Very often, values should be extracted
directly using pattern matching, to control just what gets evaluated when.
getSolo
is for convenience in situations where that is not the case:
When the result is passed to a strict function, it makes no difference whether the pattern matching is done on the "outside" or on the "inside":
Data.Set.insert (getSolo sol) set === case sol of Solo v -> Data.Set.insert v set
A traversal may be performed in Solo
in order to control evaluation
internally, while using getSolo
to extract the final result. A strict
mapping function, for example, could be defined
map' :: Traversable t => (a -> b) -> t a -> t b map' f = getSolo . traverse ((Solo $!) . f)
module Data.Typeable
mzip :: Monoid a => [a] -> [a] -> [a] Source #
Zips Monoid
values leaving trailing values.
> mzip ["ab","cd"] ["ef"] ["abef","cd"]
idIO :: (a -> IO ()) -> a -> a Source #
WARNING:
uses unsafePerformIO
and should only be used for debugging!
> idIO print 10 10 10
Return sets of values based on the list.
The values in the list must me unique.
allEqualOn :: Eq b => (a -> b) -> [a] -> Bool Source #
allEqual2 :: Eq a => [a] -> Bool Source #
Checks if all elements of a list are equal.
Exceptionally this function returns false for an empty or unit list.
This returns true when all elements are equal and the list has a length greater than or equal to two.
choicesThat :: (a -> [a] -> Bool) -> [a] -> [(a, [a])] Source #
Lists choices of values that follow a property.
foldr0 :: (a -> a -> a) -> a -> [a] -> a Source #
A variation of foldr that only uses "zero" when the list is empty
indentBy :: Int -> String -> String Source #
Indents a block of text with the provided amount of spaces
classify :: Eq a => [a] -> [[a]] #
Classify values using their Eq
instance.
> classify [1,2,3,1,2,1] [[1,1,1],[2,2],[3]]
(cf. classifyBy
, classifyOn
)
classifyBy :: (a -> a -> Bool) -> [a] -> [[a]] #
Classify values by a given comparison function.
> classifyBy (\(x,_) (y,_) -> x == y) [(1,1),(1,2),(2,1),(2,2)] [[(1,1),(1,2)],[(2,1),(2,2)]]
(cf. classify
, classifyOn
)
classifyOn :: Eq b => (a -> b) -> [a] -> [[a]] #
Classify values based on the result of a given function.
> classifyOn head ["sheep", "chip", "ship", "cheap"] [["sheep","ship"],["chip","cheap"]]
> classifyOn odd [1,2,3,4,5,6] [[1,3,5],[2,4,6]]
(cf. classify
, classifyBy
)
updateAt :: Int -> (a -> a) -> [a] -> [a] Source #
Updates the value in a list at a given position.
> updateAt 2 (*10) [1,2,3,4] [1,2,30,4]
first :: (a -> a') -> (a, b) -> (a', b) Source #
Applies a function to the first element of a pair.
Often known on the wild as mapFst
.
> first (*10) (1,2) (10,2)
second :: (b -> b') -> (a, b) -> (a, b') Source #
Applies a function to the second element of a pair.
Often known on the wild as mapSnd
.
> second (*100) (1,2) (1,200)
isSubsetOf :: Ord a => [a] -> [a] -> Bool #
O(n log n). Checks that all elements of the first list are elements of the second.