Reputation: 3195
I'm using the DuplicateRecordFields (+OverloadedLabels) extension, and I've run into a situation where I can't figure out how to disambiguate in a record update.
Here is a simplified example:
data A = A { name :: String }
data B = B { name :: String }
combine :: A -> B -> A
combine a b = a { name = name b }
Is there any way to make this work?
Upvotes: 2
Views: 1011
Reputation: 1378
Alternatively, you can mechanically use getField
from GHC.Records
to disambiguate, like this:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE TypeApplications #-}
module DRF where
import GHC.Records (getField)
data A = A { name :: String } deriving Show
data B = B { name :: String }
combine :: A -> B -> A
combine a b = a { name = getField @"name" b }
{- in ghci
Prelude DRF> a = A "Alice"
Prelude DRF> b = B "Bob"
Prelude DRF> DRF.combine a b
A {name = "Bob"}
-}
References:
Upvotes: 3
Reputation: 9179
I answered in one of the previous questions about -XDuplicateRecordFields
that currently GHC doesn't infer type of record field from its argument:
What you can do now is to specify type of name
extractor explicitly, like this:
{-# LANGUAGE DuplicateRecordFields #-}
data A = A { name :: String }
data B = B { name :: String }
combine :: A -> B -> A
combine a b = a { name = (name :: B -> String) b }
Upvotes: 2
Reputation: 120731
You could match the name from a pattern:
data A = A { name :: String }
data B = B { name :: String }
combine :: A -> B -> A
combine a B{name = nb} = a { name = nb }
I'm not a fan of DuplicateRecordFields
though. Why not instead go the lens route?
{-# LANGUAGE TemplateHaskell, FlexibleInstances, FunctionalDependencies #-}
import Control.Lens
import Control.Lens.TH
data A = A { _aName :: String }
makeFields ''A
data B = B { _bName :: String }
makeFields ''B
combine :: A -> B -> A
combine a b = a & name .~ b^.name
Upvotes: 1