wakame-0.1.0.0: test/examples/Wakame/Examples/Functions.hs
{-# LANGUAGE DuplicateRecordFields #-}
module Wakame.Examples.Functions where
import Prelude
import GHC.Generics
import Wakame
-- * Data types which is used in this module
data Point = Point { x :: Double, y :: Double }
deriving (Eq, Show, Generic)
data Position = Position { x :: !Double, y :: !Double }
deriving (Eq, Show, Generic)
data Point3d = Point3d { x :: Double, y :: Double, z :: Double }
deriving (Eq, Show, Generic)
data Tniop = Tniop { y :: Double, x :: Double }
deriving (Eq, Show, Generic)
-- | An instance of @Point@ data type.
pt :: Point
pt = Point 1.2 8.3
-- | Review of @Generic@
-- Let's review the basic functionality of an instance of @Generic@ typeclass.
--
-- `from` function converts a data to its generic representation.
-- >>> from pt
-- M1 {unM1 = M1 {unM1 = M1 {unM1 = K1 {unK1 = 1.2}} :*: M1 {unM1 = K1 {unK1 = 8.3}}}}
--
-- You can construct a representation value by hand.
-- >>> rep = M1 $ M1 $ M1 (K1 1.2) :*: M1 (K1 8.3)
--
-- From the representation value, `to` function converts back to @Point@.
-- >>> to rep :: Point
-- Point {x = 1.2, y = 8.3}
--
-- Since @Position@ has the same representation, `to` works as well.
-- >>> to rep :: Position
-- Position {x = 1.2, y = 8.3}
--
-- And even so to Tuple.
-- >>> to rep :: (Double, Double)
-- (1.2,8.3)
--
-- It is sensitive to the order of elements.
-- >>> to rep :: Tniop
-- Tniop {y = 1.2, x = 8.3}
-- * Examples of record value manipulation
-- | Round trip of Point to/from Row
-- >>> fromRow @Point $ toRow pt
-- Point {x = 1.2, y = 8.3}
-- | Converting Point to Point3d by adding z field
-- >>> fromRow @Point3d $ union (toRow pt) (toRow (keyed @"z" 42.0))
-- Point3d {x = 1.2, y = 8.3, z = 42.0}
-- | Interfacing optional fields
--
-- `f` fills absent fileds with `0.0`.
-- >>> f $ toRow (keyed @"x" 3.5)
-- Point {x = 3.5, y = 0.0}
--
-- Ignores extra fields.
-- >>> f $ toRow (keyed @"y" 4.3, keyed @"z" 1.6)
-- Point {x = 0.0, y = 4.3}
--
-- Converts from another type of data.
-- >>> f $ toRow $ Point3d 3.5 4.3 1.6
-- Point {x = 3.5, y = 4.3}
--
-- Returns fully default value when `()` is given.
-- >>> f $ toRow ()
-- Point {x = 0.0, y = 0.0}
--
-- Works nicely no matter how the order of fields is.
-- >>> f $ toRow $ Tniop 4.3 3.5
-- Point {x = 3.5, y = 4.3}
f ::
( Merge props OfPoint OfPoint
) => Row props -> Point
f props = fromRow $ merge props def
where
def :: Row OfPoint
def = toRow $ Point 0.0 0.0
type OfPoint = Of Point
-- | Filling common fields if existing
--
-- >>> g (Person "Luke" "1979-01-01") (Timestamp "2020-04-01" "2020-04-02") :: Person
-- Person {name = "Luke", created_at = "2020-04-01"}
--
-- >>> g (Point 3.5 4.3) (Timestamp "2020-04-01" "2020-04-02") :: Point
-- Point {x = 3.5, y = 4.3}
data Timestamp =
Timestamp
{ created_at :: String
, updated_at :: String
}
deriving (Eq, Show, Generic)
data Person =
Person
{ name :: String
, created_at :: String
}
deriving (Eq, Show, Generic)
g ::
( IsRow a
, IsRow b
, IsRow c
, Merge (Of b) (Of a) (Of c)
) => a -> b -> c
g x y = fromRow $ nub $ union (toRow y) (toRow x)
-- | Rejecting certain fields
--
-- `h` is the same as `g` except rejecting the first argument of having a field "y".
-- >>> h (Point 3.5 4.3) (Timestamp "2020-04-01" "2020-04-02") :: Point
-- ...
-- ... Couldn't match type ...
-- ...
h ::
( IsRow a
, IsRow b
, IsRow c
, Merge (Of b) (Of a) (Of c)
, Lacks "y" (Of a)
) => a -> b -> c
h x y = fromRow $ nub $ union (toRow y) (toRow x)