maxigit / Metamorphosis

TemplateHaskell functions to generate types and converter function.
BSD 3-Clause "New" or "Revised" License
18 stars 3 forks source link

Generate function to transform a "smaller record" to a "larger record"? #1

Open saurabhnanda opened 6 years ago

saurabhnanda commented 6 years ago

Going by this example would it be possible to generate the following function via TH:

iStyleToProduct :: Style -> String -> Int -> Product
iStyleToProduct style variation qty = undefined -- will be auto-generated via TH

There is the following comment in the example, but it is quite possible that one doesn't have the notion of a "default product".

You can easily create your own StyleToProduct function by setting default product : iStyleToProduct = iProduct'StyleToProduct myDefaultProduct

maxigit commented 6 years ago

At the moment, Metamorphosis doesn't deal with plain type (like Int and String), but I can see 3 ways to solve the problem.

The easiest would be to define it manually using the iStyle'ProductToProduct function

iStyleToProduct style variation qty = iStyleProductToProduct style product where
 product = Product undefined variation undefined  quantity

Not really elegant, but probably the simplest at the moment.

Another way, is to create two type wrapper for variation in quantity. You can do so with the following code

$(metamorphosis
   ( (\fd -> if fd ^. fdFieldName `elem` map Just ["variation", "quantity"]
             then [fd & fdTConsName .~ capitalize (fromJust  (fd ^. fdFieldName))]
             else [fd & fdTConsName .~ "Style" ])
   )
   [''Product]
   (\n -> if n `elem` ["ProductToStyle", "Product'StyleToProduct", "Quantity'Style'VariatioinToProduct"]
          then (Just identityBCR)
          else (Just applicativeBCR)
   )
   (const [''Show, ''Eq])
 )

We modified slightly the field mapping function to map quantity and variation to Quantity and Variation.

This generates

data Quantity = Quantity {quantity :: Int}
  deriving (Show, Eq)
data Variation = Variation {variation :: String ?
  deriving (Show, Eq)

but also iQuantity'Style'VariationToProduct (arguments are in alphabetic order) which (pretty much) what you need. You'll obviously need to wrap your Int and String into Quantity and Variation but I thing it's cleaner.

The third way, is to use aStyleToProduct, which already exists but needs some default value for the missing arguments. Those default values be created by adding the appropriate instance to ConvertA . You can avoid orphan instances by creating your own type wrapper around Identity.