2013-01-20 58 views
25

我说的是,这是不可能的定义:GHC Haskell为什么不支持重载记录参数名称?

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

我知道,GHC只是desugars这个平淡的功能和解决惯用的方式,这将是:

data A = A {aName :: String} 
data B = B {bName :: String} 

class Name a where 
    name :: a -> String 

instance Name A where 
    name = aName 

instance Name B where 
    name = bName 

写完后我不喜欢那么多......难道这种类型分类是否是desugaring过程的一部分?


当我编写一些Aeson JSON解析时,这个想法来到了我的脑海。对于每种数据类型,只要derive the FromJSON instances太简单了,我不得不手动将所有东西写出来(目前大于1k行和计数)。 像name或简单地value这样的名称在数据记录中并不罕见。

http://www.haskell.org/haskellwiki/Performance/Overloading提到函数重载引入了一些运行时开销。但我实际上并不明白为什么编译器无法在编译时解决这个问题,并在内部为它们指定不同的名称。

This SO question from 2012或多或少的状态历史原因和指向2006年的邮件主题。最近有什么变化吗?

即使会有一些运行时间开销,大多数人不会介意导致大多数代码几乎都是性能关键。

是否有一些隐藏的语言扩展,实际上允许这?我再次不确定......但我认为伊德里斯实际上做到了这一点?

+0

另外:有人可以添加一个伊德里斯标签SO和这个问题?也许来自该社区的人也可以详细阐述。 – fho

+0

祝贺成为第一个问题的偶像。如果您想了解更多关于这个主题的信息,可以在[ghc wiki](http://hackage.haskell.org/trac/ghc/wiki/Records)和[reddit上的对话](http:// www.reddit.com/r/haskell/comments/kgd4g/the_records_problem_in_haskell_help_build_a/)。 – Davorak

+0

感谢您的链接。 GHC文档在我的谷歌搜索结果中似乎没有很好的排名。 – fho

回答

3

使用记录语法

data A { name :: String } 

隐式定义的函数

name :: A -> String 

如果有{ name :: String }同时定义AB,我们有冲突的类型定义为name

name :: A -> String 
name :: B -> String 

是的不清楚如何你提出的隐式类型的类会因为工作,如果我们定义了两种类型的

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

那么我们刚才转移的问题冲突的类型的类定义:

class Has'name a where 
    name :: a -> String 

class Has'name a where 
    name :: a -> Text 

原则上,这是可以解决的一个这种方式或另一种方式,但这只是记录中一些棘手的相互矛盾的理想属性之一。当Haskell被定义时,决定最好是有简单的支持,而不是尝试设计更加雄心勃勃和复杂的东西。在不同的时间讨论了对记录的若干改进,并进行了长期的讨论, this Haskell Cafe thread。也许Haskell Prime会有一些解决方案。

+0

不!我们已经知道了。并拒绝它!这种脑死亡的“思想”恰恰是*问题。 他的意思是每个数据类型都有独立的名称空间!就像OOP一样,A.name与B.name不冲突。 (名称A)和(名称B)也不应该出于完全相同的原因。 我的意思是它可以在数据A {a_Name :: String}和名称为“let a = A”的情况下在内部解开“data A {name :: String}”和“let a = A”Betty“贝蒂“在aName a»。 什么是阻止? – Evi1M4chine

+4

@ Evi1M4chine:也许你应该先阅读一些关于这个问题的大量现有讨论,然后提出一些实际上并不奏效的问题,然后要求其他人实施它。 –

+0

@ Evi1M4chine那么你的例子中'name'的类型是什么?它需要有某种主体类型,否则一般的类型推断会被打破。现在,如果您不太在意向后类型推断,则可以解开开放的非内射类型族。 – semicolon

4

很多,主要是次要的原因。一个是由a better answer引发的问题,仅在第一个参数上重载不足以处理所有有用的情况。

你可以 “desugar”

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

class Has'name a b | a -> b where 
    name :: a -> b 

data A { aName :: String } 
instance Has'name A String where 
    name :: aName 

data B { bName :: Text } 
instance Has'name B Text where 
    name :: bName 

但这需要还没有使它成为标准,但GHC扩展(函数依赖)。它不会仅仅使用'名称'来创建记录,更新和模式匹配(视图模式可能会有所帮助),因为'name'在这些情况下不是“仅仅”的函数。你也许可以拿出与模板Haskell非常相似的东西。

+0

这不能解决多态更新或做页面上的其他类型 –

+0

如果你需要做多态更新,你应该仍然可以在类型类中定义“name”,但要确保它具有类型Functor f =>(a - > fb) - > s - > ft(或某种“关闭”),以便它可以用作镜头。 尽管如此,我通常会在有不同镜头的不同名称(如果长的话)上通过合格进口出错。 –

0

我发现的最好方法是使用预处理器来解决这个绝对相当愚蠢的问题。

Haskell和GHC使这很容易,因为整个Haskell解析器可用作普通库。你可以解析所有的文件,将名称为a的数据重命名方案(例如“data A {name :: String}”和“let a = A”Betty“)转换为”data A {a_Name :: String}“和”根据名称函数应用于的数据类型,使用类型解析器将a = A“Betty”放入aName a»),然后写出来进行编译。

但说实话,这应该被整合到GHC中。你是对的:愚蠢的是,这不包括在内。

+0

但并非所有类型在编译时都是已知的,所以您不得不担心诸如主体类型之类的事情。你的例子中'name'的类型是什么?它必须具有一种类型才能在类型推断等方面与Haskell的其他部分一起工作良好。例如,如果'A'和'B'都是'Monoid'的一个实例,'name mempty'会给你带来什么? – semicolon

相关问题