考虑以下:
{-# LANGUAGE DuplicateRecordFields #-}
data A = A { name :: String }
data B = B { name :: String }
main = print $ name (A "Alice")
Run Code Online (Sandbox Code Playgroud)
编译时,我得到以下消息(在GHC 8.0.2上)
duplicatedrecords.hs:7:16: error:
Ambiguous occurrence ‘name’
It could refer to either the field ‘name’,
defined at duplicatedrecords.hs:5:14
or the field ‘name’, defined at duplicatedrecords.hs:3:14
Run Code Online (Sandbox Code Playgroud)
但如果我main按如下方式修改该行:
main = print $ name ((A "Alice") :: A)
Run Code Online (Sandbox Code Playgroud)
编译成功完成.
为什么是这样?类型签名:: A对我来说似乎是多余的,因为A构造函数肯定会使(A "Alice")类型的编译器清楚A.但由于某种原因,它会产生影响.为什么这样,有没有一种方法可以让我编译而不会乱丢额外的类型签名?
注意:
值得注意的是,以下编译正常:
data A = A { a_name :: String }
data B = B { b_name :: String }
class Name t where
name :: t -> String
instance Name A where name = a_name
instance Name B where name = b_name
main = print $ name (A "Alice")
Run Code Online (Sandbox Code Playgroud)
我们甚至可以进一步如下,允许不同的结果类型:
{-# LANGUAGE TypeFamilies #-}
data A = A { a_name :: String }
data B = B { b_name :: Int }
class Name t where
type family T t
name :: t -> T t
instance Name A where
type T A = String
name = a_name
instance Name B where
type T B = Int
name = b_name
main = print $ name (A "Alice")
Run Code Online (Sandbox Code Playgroud)
似乎GHC只需要为每个唯一记录名称机械地添加一个类,并为每个数据类型中的每个记录添加一个实例.然而,name x == name y这意味着并不意味着类型x和y相同,但我仍然期望在使用此扩展时.
只是想知道这里是否有任何棘手的问题,或者只是需要有人这样做?
-XDuplicateRecordFields 目前不会从参数推断出类型.
但是,我们不会推断参数的类型来确定数据类型,或者有任何方法可以将选择推迟到约束求解器.因此以下是不明确的:
但事情正在改善.所以我们可能期望并最终得到理想的行为:
https://prime.haskell.org/wiki/TypeDirectedNameResolution