有人能解释一下数据/类型构造函数和函数之间有什么区别吗? Haskell混合它们并给我们一个通用接口(所有看起来像函数,特别是,我们可以部分应用它们),而ML家族语言区分它们。
答案 0 :(得分:18)
你的二分法“Haskell与ML世界”是错误的¹。 SML还将构造函数提升为函数,而Caml Light曾经使用过。我不确定为什么它在OCaml中删除了,我认为设计师认为没有真正需要它。
有很多原因可以解释为什么构造函数略显特殊。它们可以用于模式,而一般功能则不能 - 我想这可以用极化逻辑和聚焦来解释。此外,应用于值的构造函数可以被视为值,而对于一般函数则不是这样。在值调用语言中,通常将递归值定义限制为允许构造函数应用程序的子类,而不是通用函数应用程序。
我同意将所有构造函数提升为函数的“语义糖”很好。然而,我认为如果我们有一个很好的语法糖用于短抽象,例如Scala的Some(_)
,那么这将不会那么有用。
在我看来,构造函数是否应该被改为(你的“部分应用”评论)是一个不同的正交问题。
¹:除了错误的二分法之外,你问题的基调还有一种“Haskellers and MLers,这就是戒指,请打架!”。这可能不是故意的,但无论如何你应该避免这样的表述。语言设计是由妥协构成的,假设当两种不同的语言做出不同的选择时,其中一种语言正确而另一种语言不是一种好的方法。
PS:这个问题已被编辑,现在更加中立。谢谢你的编辑。
²:根据petebu的要求,这里有一些关于“聚焦和极性”的信息(实际上还有很多)。我想指出,我真的不是这个主题的专家(因此“我猜”)。
我首先推荐Neelakantan Krishnaswami撰写的论文Focusing on Pattern Matching (PDF),2009年。它包含对不熟悉极化逻辑和聚焦的人的介绍(但你需要至少熟悉后续的微积分)。通常在后续的微积分中,类型/命题被“在右边”引入并且在“左边”被消除/解构。但是在这里我们将类型分为“极性”,产品和总和是积极的,功能是负的(我的直觉是产品/总和是数据,而功能是计算,但分离是由他们在后续微积分中的行为的非常自然的考虑所驱动的),并且该论文表明,箭头类型的左消除对应于功能应用,而总和/产品类型的左消除对应于模式匹配。有一个case
构造,其行为类似于模式匹配(有一些差异),消除了正面因素,因此无法应用于函数。
另一个重要的参考文献是Focusing on Binding and Computation,Dan Licata,Noam Zeilberger和Robert Harper,2008年(请注意,如果您计划提交有关这些主题的论文,“专注于...”是变得有点陈词滥调)。它更少强调与ML风格模式匹配的联系,但引入了一个非常好的想法,即虽然计算箭头“左侧为负”(很容易被视为经典等价A→B ≡ ¬A∨B
),但可以引入不同的箭头,“左侧为正”,因此正极化,可以是模式匹配的。事实证明,这个箭头是表示变量绑定的一个很好的匹配(如果你熟悉高阶抽象语法,那么这个想法就是左极性排除试图计算其变量的“异国术语”),这样带有变量绑定的术语是可以像总和或产品一样进行模式匹配的数据结构
我发现他们的论文有点难以阅读,所以我会从Dan Licata's slides开始。最后,罗伯特·哈珀提出了other slides,它在归纳判断/推导中提供了不同的直觉:正箭头表示可导性(你可以在假设A和B下构建C的推导) ?)而负箭头表示可接受性(给定A和B的派生,你将如何重写/探索/操纵它们来构建C的派生?)。非常有趣的东西。
答案 1 :(得分:1)
首先必须解释值和类型之间的区别。
“因为Haskell是一种纯函数式语言,所有计算都是通过表达式(句法术语)的评估来完成的,以产生值(我们认为是答案的抽象实体)。每个值都有一个相关的类型。” - 温和地介绍Haskell 98(本教程不太温和)
Haskell值是“一等”,而Haskell类型则不是。类型用于描述值,值与其类型的关联称为键入。
数据/类型构造函数之间的区别在于:应用数据构造函数会产生一个值,但应用类型构造函数会产生一个类型。
函数只是描述值的表达式,它与一个类型相关联。在评估函数时,您只是在评估描述值的表达式。
答案 2 :(得分:0)
Haskell确实减少并简化了一些OCaml语法。但是Haskell语法确实明确区分了构造函数和函数。函数以小写字母开头,构造函数以大写字母开头。对于中缀运算符,数据构造函数必须以冒号开头,而普通运算符可能永远不会以冒号开头。
构造函数的接口看起来像简单(可能是部分)函数应用程序,这使得一个参数构造函数和大多数newtypes非常容易使用(只需“hello”)。但是Haskell确实允许你使用类似OCaml的记录名和{field = value,field = value}样式,但在Haskell中你不必强制使用字段名称或强制使用这种语法。因此,OCaml只有单个字段的简单语法,但Haskell允许您为多个字段提供简单的语法。最终,避免使用字段名称对于大型类型是不利的,因为类似位置函数的语法更难以重构。