Haskell 使用DuplicateRecordFields消除记录更新的歧义

Haskell 使用DuplicateRecordFields消除记录更新的歧义,haskell,records,ambiguous-call,Haskell,Records,Ambiguous Call,我正在使用DuplicateRecordFields(+OverloadedLabels)扩展,我遇到了一种无法在记录更新中消除歧义的情况 以下是一个简化的示例: data A = A { name :: String } data B = B { name :: String } combine :: A -> B -> A combine a b = a { name = name b } 有什么方法可以让这个工作正常吗?您可以从模式中匹配名称: data A = A { n

我正在使用DuplicateRecordFields(+OverloadedLabels)扩展,我遇到了一种无法在记录更新中消除歧义的情况

以下是一个简化的示例:

data A = A { name :: String }
data B = B { name :: String }

combine :: A -> B -> A
combine a b = a { name = name b }

有什么方法可以让这个工作正常吗?

您可以从模式中匹配名称:

data A = A { name :: String }
data B = B { name :: String }

combine :: A -> B -> A
combine a B{name = nb} = a { name = nb }
不过,我不喜欢重复记录字段。为什么不去呢


我在前面关于
-XDuplicateRecordFields
的一个问题中回答说,目前GHC没有从其参数推断出记录字段的类型:

您现在可以做的是显式指定
name
提取器的类型,如下所示:

{-# 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 }
{-# 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"}

-}

或者,您可以机械地从
GHC.Records
使用
getField
来消除歧义,如下所示:

{-# 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 }
{-# 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"}

-}
参考资料:


使用
-XNamedFieldPuns
,我们还可以编写
组合一个B{name}=a{name=name}
@danidiaz我们可以这样做吗?好吧,如果你这么说的话。在我看来,无论如何,我们不应该这样做
{name=name}
看起来非常混乱。所有这些扩展都是旧记录系统中的单向黑客行为,这种方式无法很好地工作。当
OverloadedRecordFields
将通过
HasField
类和magic hash语法正常工作时,这将是一双不同的鞋,但在此之前,我将坚持镜头库提供的功能。