agreeing 0.2.0.0 → 0.2.1.0
raw patch · 4 files changed
+64/−11 lines, 4 files
Files
- CHANGELOG.md +5/−1
- README.md +12/−0
- agreeing.cabal +2/−2
- src/Data/Agreement.hs +45/−8
CHANGELOG.md view
@@ -6,6 +6,10 @@ and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## 0.2.1.0 - 2023-10-30++* `Eq`, `Ord`, `Show`, `Applicative` and `Monad` instances+ ## 0.1.0.0 - 2023-03-15 - Initial version+Initial version
README.md view
@@ -2,3 +2,15 @@ A simple data structure helping us ask questions of the following sort: "does all this data have the same /BLANK/ and if so what is it?"++For example:++ doTheseHaveTheSameLength :: [String] -> String+ doTheseHaveTheSameLength l = case foldMap (Somebody . length) of+ Somebody n -> "They all have length " <> show n+ Nobody -> "The lengths differ"+ Anybody -> "You didn't give me any strings"++This can of course be done with `Maybe (Maybe x)` instead, but doing+so runs the risk of getting confused: which is `Nothing` and which is+`Just Nothing`?
agreeing.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.2.+-- This file has been generated from package.yaml by hpack version 0.36.0. -- -- see: https://github.com/sol/hpack name: agreeing-version: 0.2.0.0+version: 0.2.1.0 synopsis: Idiomatic data structure for agreement description: Please see the README on GitHub at <https://github.com/jcranch/agreeing#readme> category: Data
src/Data/Agreement.hs view
@@ -9,6 +9,26 @@ -- > Somebody n -> "They all have length " <> show n -- > Nobody -> "The lengths differ" -- > Anybody -> "You didn't give me any strings"+--+-- This can of course be done with `Maybe (Maybe x)` instead, but+-- doing so runs the risk of getting confused: which is `Nothing` and+-- which is `Just Nothing`?+--+-- Unfortunately, there are two `Applicative` instances.+--+-- One is easy to motivate intrinsically. If we think of `Anybody` as+-- an empty list, `Somebody` as a singleton list, and `Nobody` as a+-- multi-element list, and think of the applicative instance on as+-- corresponding to the cartesian product, then we get an+-- `Applicative` instance with+--+-- > Anybody <*> Anybody = Anybody+-- > Anybody <*> Nobody = Nobody+--+-- This however cannot possibly correspond to a `Monad` instance (if+-- the first argument of `>>=` is Anybody, there's no way of+-- inspecting the second). We thus choose another, which does.+ module Data.Agreement ( Agreement(..), getSomebody,@@ -25,6 +45,7 @@ -- -- * `Anybody` is a failure to make any choice. data Agreement a = Anybody | Somebody a | Nobody+ deriving (Eq, Ord, Show) -- | This picks out consistent choices as `Just`. getSomebody :: Agreement a -> Maybe a@@ -32,18 +53,34 @@ getSomebody _ = Nothing instance Functor Agreement where- fmap _ Anybody = Anybody+ fmap _ Anybody = Anybody fmap f (Somebody x) = Somebody (f x)- fmap _ Nobody = Nobody+ fmap _ Nobody = Nobody +-- | Not the only possible instance: see introduction+instance Applicative Agreement where+ pure = Somebody+ Nobody <*> _ = Nobody+ Anybody <*> _ = Anybody+ Somebody f <*> x = f <$> x+ liftA2 _ Nobody _ = Nobody+ liftA2 _ Anybody _ = Anybody+ liftA2 f (Somebody x) y = f x <$> y++instance Monad Agreement where+ return = pure+ Nobody >>= _ = Nobody+ Anybody >>= _ = Anybody+ Somebody x >>= f = f x+ instance (Eq a) => Semigroup (Agreement a) where- Anybody <> x = x- Nobody <> _ = Nobody- Somebody x <> Anybody = Somebody x- Somebody _ <> Nobody = Nobody+ Nobody <> _ = Nobody+ Anybody <> x = x+ Somebody _ <> Nobody = Nobody+ Somebody x <> Anybody = Somebody x Somebody x <> Somebody y- | x == y = Somebody x- | otherwise = Nobody+ | x == y = Somebody x+ | otherwise = Nobody stimes = stimesIdempotentMonoid instance (Eq a) => Monoid (Agreement a) where