Skip to content

Commit

Permalink
Merge pull request #231 from input-output-hk/anviking/quantity-docs
Browse files Browse the repository at this point in the history
New take on Data.Quantity documentation
  • Loading branch information
Anviking committed May 7, 2019
2 parents 53f16d2 + 2390a8d commit fb20bfc
Showing 1 changed file with 29 additions and 14 deletions.
43 changes: 29 additions & 14 deletions lib/core/src/Data/Quantity.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,32 +52,47 @@ import GHC.TypeLits
import qualified Data.Text as T


-- | Represents a value that has an associated unit of measure, based on some
-- underlying type.
-- | @Quantity (unit :: Symbol) a@ is a primitive @a@ multiplied by an @unit@.
--
-- >>> newtype Amount = Amount (Quantity "lovelace" Word32)
newtype Quantity (u :: Symbol) a = Quantity a
-- Example:
--
-- Instead of providing the unit implicitly as a comment, or a part of a name
--
-- >>> a :: Word32 -- in lovelace
--
-- we can write
--
-- >>> a :: Quantity "lovelace" Word32
--
-- which now has a different type from
--
-- >>> b :: Quantity "lovelace/byte" Word32
--
-- so mixing them up is more difficult.
--
-- The unit is mostly a phantom type, but it is also included in the
-- @ToJSON@/@FromJSON@ instances.
--
-- >>> Aeson.encode $ Quantity @"lovelace" 14
-- {"unit":"lovelace","quantity":14}
newtype Quantity (unit :: Symbol) a = Quantity a
deriving stock (Generic, Show, Eq, Ord)
deriving newtype (Bounded, Enum)

instance NFData a => NFData (Quantity u a)
instance NFData a => NFData (Quantity unit a)

-- | Encode to JSON delegating the
--
-- >>> Aeson.encode $ Quantity @"lovelace" 14
-- {"unit":"lovelace","quantity":14}
instance (KnownSymbol u, ToJSON a) => ToJSON (Quantity u a) where
instance (KnownSymbol unit, ToJSON a) => ToJSON (Quantity unit a) where
toJSON (Quantity a) = object
[ "unit" .= symbolVal (Proxy :: Proxy u)
[ "unit" .= symbolVal (Proxy :: Proxy unit)
, "quantity" .= toJSON a
]

instance (KnownSymbol u, FromJSON a) => FromJSON (Quantity u a) where
instance (KnownSymbol unit, FromJSON a) => FromJSON (Quantity unit a) where
parseJSON = withObject "Quantity" $ \o -> do
verifyUnit (Proxy :: Proxy u) =<< o .: "unit"
verifyUnit (Proxy :: Proxy unit) =<< o .: "unit"
Quantity <$> o .: "quantity"
where
verifyUnit :: Proxy (u :: Symbol) -> Value -> Parser ()
verifyUnit :: Proxy (unit :: Symbol) -> Value -> Parser ()
verifyUnit proxy = \case
String u' | u' == T.pack u -> pure ()
_ -> fail $
Expand Down

0 comments on commit fb20bfc

Please sign in to comment.