Haskell记录语法 [英] Haskell record syntax

查看:150
本文介绍了Haskell记录语法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Haskell的记录语法被许多人认为是对其他优雅语言的一种讽刺,因为它的丑陋语法和命名空间污染。另一方面,它通常比基于位置的替代方案更有用。



而不是像这样的声明:

  data Foo = Foo {
fooID :: Int,
fooName :: String
}派生(显示)

在我看来,沿着这些路线的东西会更有吸引力:

  data Foo = Foo id: :Int 
name :: String
deriving(显示)

我是肯定有一个很好的理由,我错过了,但为什么类似C语言的记录语法通过一个更清晰的基于布局的方法?

其次,有什么在管道中解决命名空间问题,因此我们可以在未来版本的Haskell中编写 id foo 而不是 fooID foo ? (除了目前可用的longwinded基于类的变通方法外)。

解决方案

那么如果没有其他人会尝试,那么我我会采取另一个(稍微更仔细的研究)刺回答这些问题。

tl; dr

问题1:这只是掷骰子的方式。这是一个环境选择,它卡住了。



问题2:是(sorta)。有几个不同的团体肯定在考虑这个问题。

请阅读关于每个答案的非常长的解释,以我发现的链接和引用为基础相关的和有趣的。

为什么采用基于布局的更清晰的C语言语法?



微软研究人员写了一篇 Haskell的历史论文。第5.6节讨论记录。我将引用第一个很有意思的小插曲:
$ b blockquote>

Haskell早期版本中最明显的遗漏之一
是没有记录,提供了命名的领域。鉴于
记录在实践中非常有用,为什么它们被省略了?


然后Microsoft们回答他们自己的问题 p>


最强烈的原因似乎是没有明显的正确设计。


您可以自己阅读这篇文章以获取详细信息,但他们表示Haskell最终采用了记录语法,因为数据结构中命名字段的压力。


到Haskell 1.3设计开始的时候,在1993年,用户对数据结构中命名域的
压力很大,因此委员会最终采用了极简主义设计...


你问为什么这是为什么?那么,据我所知,如果早期的Haskellers有他们的方式,我们可能从来没有记录语法。这个想法显然已经被那些已经习惯了类C语法的人推到了Haskell上,并且更有兴趣将类似C的东西变成Haskell,而不是Haskell的方式。 (是的,我意识到这是一个非常主观的解释,我可能是错的,但如果没有更好的答案,这是我可以得出的最好结论。)



有没有什么可以解决命名空间问题? 首先,并不是每个人都感觉到它是一个问题。几周前,一位球拍爱好者向我(和其他人)解释说,具有相同名称的不同功能是一个坏主意,因为它会使分析函数名称___做什么变得复杂。事实上,这不是一种功能,而是许多功能。对于Haskell来说,这个想法可能会很麻烦,因为它会使类型推断变得复杂。



微软有一点关于Haskell的类型特性有趣的说法:


Wadler和Blott恰巧在语言时刻产生这个关键概念
时,巧合的是
的时间设计仍然在流行。


不要忘记Haskell曾经很年轻。有些决定仅仅是因为它们的制作而成的。



无论如何,有一些有趣的方式可以解决这个问题:

键入定向名称解析,一个建议修改Haskell(在上面的评论中提到)。只要阅读该页面即可看到它涉及该语言的很多领域。总而言之,这不是一个坏主意。已经考虑了很多想法,以便它不会与东西发生冲突。然而,它仍然需要更多的注意力才能将其引入现在(更成熟)的Haskell语言中。



另一篇微软论文 OO Haskell ,特别提出了将Haskell语言扩展为支持特设超载。这很复杂,所以你只需要自己检查第4部分。它的要点是自动(?)推断有类型,并添加一个额外的步骤来键入检查他们称之为改善,在下面的选择性引用中模糊地概述:


给定类约束 Has_m(Int - > C - > r)
只有一个m的实例匹配这个约束...因为只有一个选择,所以我们现在应该做到这一点,并且反过来
修复 r 诠释。因此,我们得到 f 的预期类型:
f :: C - > Int - > IO Int ... [这]只是一个
的设计选择,一个基于 Has_m 已关闭


对于不相干引用的道歉;如果这对你有所帮助,那么很好,否则就去阅读论文。这是一个复杂的(但令人信服的)想法。



Chris Done使用了Template Haskell来提供在Haskell中输入鸭子与OO Haskell文件(使用Has类型)模糊地类似。来自他的网站的一些互动会话样本:

 λ>襟翼^。唐纳德
*皮瓣皮瓣*
λ>襟翼^。克里斯
我挥舞着我的手臂!

fly ::(Has Flap duck)=>鸭 - > IO()
fly duck = do go;走;去哪里=襟翼^。鸭

λ> fly donald
*翻盖翻盖*
*翻盖翻盖*
*翻盖翻盖*

这需要一些样板/不寻常的语法,我个人更喜欢坚持使用类型类。但是对克里斯·多恩自由地发表他在该地区踏实的工作表示赞赏。


Haskell's record syntax is considered by many to be a wart on an otherwise elegant language, on account of its ugly syntax and namespace pollution. On the other hand it's often more useful than the position based alternative.

Instead of a declaration like this:

data Foo = Foo { 
  fooID :: Int, 
  fooName :: String 
} deriving (Show)

It seems to me that something along these lines would be more attractive:

data Foo = Foo id   :: Int
               name :: String
               deriving (Show)

I'm sure there must be a good reason I'm missing, but why was the C-like record syntax adopted over a cleaner layout-based approach?

Secondly, is there anything in the pipeline to solve the namespace problem, so we can write id foo instead of fooID foo in future versions of Haskell? (Apart from the longwinded type class based workarounds currently available.)

解决方案

Well if no one else is going to try, then I'll take another (slightly more carefully researched) stab at answering these questions.

tl;dr

Question 1: That's just the way the dice rolled. It was a circumstantial choice and it stuck.

Question 2: Yes (sorta). Several different parties have certainly been thinking about the issue.

Read on for a very longwinded explanation for each answer, based around links and quotes that I found to be relevant and interesting.

Why was the C-like record syntax adopted over a cleaner layout-based approach?

Microsoft researchers wrote a History of Haskell paper. Section 5.6 talks about records. I'll quote the first tiny bit, which is insightful:

One of the most obvious omissions from early versions of Haskell was the absence of records, offering named fields. Given that records are extremely useful in practice, why were they omitted?

The Microsofties then answer their own question

The strongest reason seems to have been that there was no obvious "right" design.

You can read the paper yourself for the details, but they say Haskell eventually adopted record syntax due to "pressure for named fields in data structures".

By the time the Haskell 1.3 design was under way, in 1993, the user pressure for named fields in data structures was strong, so the committee eventually adopted a minimalist design...

You ask why it is why it is? Well, from what I understand, if the early Haskellers had their way, we might've never had record syntax in the first place. The idea was apparently pushed onto Haskell by people who were already used to C-like syntax, and were more interested in getting C-like things into Haskell rather than doing things "the Haskell way". (Yes, I realize this is an extremely subjective interpretation. I could be dead wrong, but in the absence of better answers, this is the best conclusion I can draw.)

Is there anything in the pipeline to solve the namespace problem?

First of all, not everyone feels it is a problem. A few weeks ago, a Racket enthusiast explained to me (and others) that having different functions with the same name was a bad idea, because it complicates analysis of "what does the function named ___ do?" It is not, in fact, one function, but many. The idea can be extra troublesome for Haskell, since it complicates type inference.

On a slight tangent, the Microsofties have interesting things to say about Haskell's typeclasses:

It was a happy coincidence of timing that Wadler and Blott happened to produce this key idea at just the moment when the language design was still in flux.

Don't forget that Haskell was young once. Some decisions were made simply because they were made.

Anyways, there are a few interesting ways that this "problem" could be dealt with:

Type Directed Name Resolution, a proposed modification to Haskell (mentioned in comments above). Just read that page to see that it touches a lot of areas of the language. All in all, it ain't a bad idea. A lot of thought has been put into it so that it won't clash with stuff. However, it will still require significantly more attention to get it into the now-(more-)mature Haskell language.

Another Microsoft paper, OO Haskell, specifically proposes an extension to the Haskell language to support "ad hoc overloading". It's rather complicated, so you'll just have to check out Section 4 for yourself. The gist of it is to automatically (?) infer "Has" types, and to add an additional step to type checking that they call "improvement", vaguely outlined in the selective quotes that follow:

Given the class constraint Has_m (Int -> C -> r) there is only one instance for m that matches this constraint...Since there is exactly one choice, we should make it now, and that in turn fixes r to be Int. Hence we get the expected type for f: f :: C -> Int -> IO Int...[this] is simply a design choice, and one based on the idea that the class Has_m is closed

Apologies for the incoherent quoting; if that helps you at all, then great, otherwise just go read the paper. It's a complicated (but convincing) idea.

Chris Done has used Template Haskell to provide duck typing in Haskell in a vaguely similar manner to the OO Haskell paper (using "Has" types). A few interactive session samples from his site:

λ> flap ^. donald
*Flap flap flap*
λ> flap ^. chris
I'm flapping my arms!

fly :: (Has Flap duck) => duck -> IO ()
fly duck = do go; go; go where go = flap ^. duck

λ> fly donald
*Flap flap flap*
*Flap flap flap*
*Flap flap flap*

This requires a little boilerplate/unusual syntax, and I personally would prefer to stick to typeclasses. But kudos to Chris Done for freely publishing his down-to-earth work in the area.

这篇关于Haskell记录语法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆