Haskell是一种强类型编程语言吗?

29

Haskell的类型系统是强类型的吗?也就是说,分配了变量后是否可以更改其类型?我在互联网上找不到答案。


11
Haskell 是否是强类型语言取决于你是否喜欢它的类型系统。参见 http://ericlippert.com/2012/10/15/is-c-a-strongly-typed-or-a-weakly-typed-language/。 - Eric Lippert
11
“Strongly-typed”和“weakly-typed”这两个术语定义不清楚。你可能是想问Haskell是否动态类型(不是)。 - Colonel Thirty Two
14
请注意,在 Haskell 中,即使它是动态类型语言,你也无法在赋值后改变变量的;因此变量的运行时类型在分配时就被固定了。 - ruakh
@EricLippert,将_weak = type-unsafe_和_strong = type-safe_进行映射怎么样?下面是我版本中定义的其余部分。然而,我认为memsafety——如果你指的是内存分配和指针解引用——应该被视为比类型安全性更低一层,而类型安全性又比静态类型安全性低一层。 - Erik Kaplun
4
感谢您恰如其分地阐明了我的核心观点:这些术语定义不清,必须经过仔细的解释,明确要表达哪种安全性和保证。此外,对于像 C# 这样大部分是类型安全但有一个与 C 程序交互时不安全的子集的语言,应该怎么处理呢?这样的语言是强类型还是弱类型?是因为通常是类型安全而被认为是强类型还是因为可能不安全而被认为是弱类型?同样地,我们必须仔细划定我们的意思。 - Eric Lippert
4个回答

101

静态 - 类型在编译时已知。Java和Haskell具有静态类型。还包括C / C ++,C#,Go,Scala,Rust,Kotlin,Pascal等。

静态类型语言可能具有类型推断,也可能没有。 Java几乎完全缺乏类型推断(但它正在很慢地稍微改变); Haskell具有完整的类型推断(除了某些非常高级的扩展之外)。

(类型推断是指您只需手动声明最少量的类型,例如var isFoo = truevar person = new Person(),而不是bool isFoo = ...Person person = ...。)

动态 - Python,JavaScript,Ruby,PHP,Clojure(以及Lisp总体),Prolog,Erlang,Groovy等。也可以称为“一种类型”;动态类型可以在静态设置中“模拟”,但反之则不成立,除非使用外部静态分析工具。一些语言使混合动态和静态成为可能(参见渐进类型,例如:https://typedclojure.org/)。

一些语言允许为一个或多个模块启用静态类型,应用于导入时间,例如:Python+MypyTyped ClojureJavaScript+FlowPHP+Hack等。

- 所有想要被视为Cat的值都将被视为Cat;试图将它们视为Dog将导致一个大声的meeewww……我是指错误。

- 这实际上归结为2个相似但不同的事物:类型强制转换(例如,在PHP中,"5"+3等于8 - 或者是吗!)和内存重新解释(例如,在C中的(int) someCharValue(bool) somePtr以及C ++中也是如此,但是C ++希望您明确说明reinterpret_cast)。因此,实际上有强制-弱重新解释-弱之分,不同的语言在这两种方式中都是弱的。

有趣的是,注意强制转换天生就是隐式的,而内存重新解释是显式的(除了汇编语言)。因此,弱类型由一个隐式和一个显式的行为组成。也许这更是将弱类型归为两个不同的子类别的原因。


有一些语言包括所有4种可能的组合以及变体/渐变。
Haskell是静态+强类型的;当然,它有unsafeCoerce,所以有时会是静态+弱类型,但是unsafeCoerce在除了极端情况下都不太受欢迎,除非您确定某个情况,并且无法说服编译器而不是返回并以不同的方式重新讲述整个故事。
C是静态+弱类型的,因为所有内存都可以自由地被重新解释为原本不应包含的内容,因此薄弱。但是,所有这些重新解释都由类型检查器跟踪,因此仍然完全静态。但是,C不进行隐式强制转换,因此只是重新解释弱化。
Python是动态+几乎完全强类型的-在执行到达该行代码之前,任何给定行上都没有已知的类型,但是在运行时存在的值确实与其关联的类型,因此不可能重新解释内存。隐式强制转换也被保持在有意义的最小限度内,因此可以说Python是99.9%的强类型和0.01%的强制转换弱类型。
PHP和JavaScript是动态+大多数弱类型-dynamic,表示在执行和内省其内容之前,没有任何类型,也是弱类型的,因为强制转换一直发生,并且使用内置操作而不是仅调用方法和函数的情况下,您永远不会真正期望进行强制转换。这些强制转换是互联网上很多幽默的来源。没有内存重新解释,因此PHP和JS是强制转换-弱类型。
此外,一些人喜欢认为静态类型是变量具有类型,而强类型是值具有类型-这是了解整个情况的非常有用的方式,但它并不完全正确:某些动态类型的语言还允许对变量/参数进行注释,以在运行时强制执行。
在静态类型中,表达式具有类型;变量具有类型的事实仅是从较小的表达式组合成更大的表达式的手段,因此它不是变量本身具有类型。
同样,在动态类型中,不是变量缺少静态已知类型,而是所有表达式都缺少类型!变量缺乏类型仅是由于存储它们的表达式缺乏类型。
最后一个例子:在动态类型中,所有猫,狗甚至大象(实际上是整个动物园!)都被打包在具有相同尺寸的箱子中。
在静态类型中,这些箱子看起来不同,并带有标签说明里面装的是什么。
有些人喜欢它,因为他们可以只使用单个框体系,并且不必在框上贴任何标签-仅框架的排列(并希望)提供类型正常性。

有些人喜欢它是因为它允许他们在装有闻起来像狮子的盒子中暂时运输老虎,并将熊放置在与狼或鹿相连的盒子阵列中进行各种花招。

在这种没有标签的运输箱设置中,所有可能的逻辑场景需要播放或模拟,以便检测隐式排列中的不对齐情况,就像在舞台表演中一样。一般而言,仅凭推理无法给出可靠的保证。(需要启动整个系统才能得出其健全性的部分结论的即兴测试用例)

通过为各种标签的盒子添加标签和显式规则,可以使用自动化/机械化的逻辑推理来得出有关物流系统不会执行或肯定会执行的结论(静态验证、形式证明或至少类似QuickCheck的伪证明)。物流的某些方面仍然需要通过试运行进行验证,例如物流团队是否正确理解了客户要求。(集成测试、验收测试、最终用户合理性检查)。


此外,在弱类型语言中,狗可以被切割并重新组装成弗兰肯斯坦猫。无论它们喜欢与否,结果是否难看。(弱类型)

但是,如果您为盒子添加标签,仍然很重要将弗兰肯斯坦猫放入猫的盒子中。(静态+弱类型)


在强类型语言中,虽然您可以将猫放入狗的箱子中,但只有在您尝试通过喂它只有狗才会吃的东西来羞辱它时,才能继续假装它是一只狗——如果发生这种情况,它会大声尖叫,但在那之前,在动态类型环境中,它会默默地接受自己的位置(在静态世界中,它会拒绝被放入狗的盒子中,还没等你说出“小猫”)。


4
在一条英文句子中嵌套这么多括号真的有必要吗?你很快就会开始用Lisp语言了……(例如:在PHP中,“5”+3等于8(还是等于8呢? ;)))) - recursion.ninja
2
那么 Python 的另外 0.89% 是什么呢? ;) - Darael
6
@Darael: 争论某些东西是否符合 Pythonic 风格。 - Steve Jessop
3
@Voo:通过一个足够强大的类型系统,你可以用类型来编码业务需求。Ocsigen是一个OCaml编写的网络框架,无法生成格式错误的HTML,任何尝试这样做的操作都会导致类型错误。Ur/Web是一个使用Ur编写的网络框架,无法生成格式错误的HTML、死链、SQL注入、跨站脚本攻击、没有验证的HTML表单,任何尝试这样做的操作都会导致类型错误。Galois是一家使用Haskell编写政府、军事和情报软件的公司,他们已经将分发机密信息的规则编码到了软件中… - Jörg W Mittag
2
在类型系统中添加文档可以避免编写违反机密性的代码。即使一个邪恶的攻击者能够将插件注入到Galois政府CMS中,也不可能泄露任何信息,因为它无法编译。而且这还没有涉及像Agda、Idris、Epigram、Coq、Isabelle这样的依赖类型语言,你可以将任何逻辑表达式编码为类型。 - Jörg W Mittag
显示剩余17条评论

9
您似乎混淆了动态/静态和弱/强类型。动态或静态类型是关于变量类型是否可以在执行期间更改。弱或强类型是关于能否仅从函数签名预测类型错误。Haskell既是静态类型又是强类型。然而,在Haskell中没有变量这样的东西,因此谈论动态或静态类型毫无意义,因为每个赋值给标识符的值都不能在执行期间更改。编辑:但像goldenbull所说,这些类型概念并没有明确定义。

2
强类型本身并不能让你预测任何事情;它只是确保猫最终不会像狗一样被对待(想想那对猫来说有多可怕...)。只有强类型与静态结合才能提供这一点;但再次强调,即使是静态+弱类型也提供了很多可预测性。 - Erik Kaplun

0

-1

我认为你在谈论两件不同的事情。

首先,Haskell和大多数函数式编程(FP)语言都没有“变量”这个概念。相反,它们使用“名称”和“值”的概念,只是将一个值“绑定”到一个名称上。一旦值被绑定,就不能再将另一个值绑定到同一个名称上,这是FP的关键特征。

强类型是另一个话题。是的,Haskell是强类型的,大多数FP语言也是强类型的。强类型赋予FP“类型推断”的能力,这种能力可以在编译时消除隐藏的错误,并帮助减少源代码的大小。

也许你正在将Haskell与Python进行比较?Python也是强类型的。Haskell和Python之间的区别在于“静态类型”和“动态类型”。术语“强类型”和“弱类型”的实际含义是模糊不清的。这是另一个漫长的故事……


3
抱歉,您混淆了“strong”和“static”,并提到了“type checking”,但实际上讨论的是“type inference”。强类型赋予函数式编程“类型推断”的能力,这种能力在编译时可以有效消除隐藏的错误,并有助于减少源代码的大小。 - Erik Kaplun
5
我们确实有变量的概念;我们只是用这个词有些不同。在函数式语言中,变量很像一个数学变量。 - dfeuer
@goldenbull: 顺便提一下,“变量”的概念不仅仅是你强调的区别 —— 例如,数学函数有一个明确的“变量”概念(和参数和常量);由于Haskell实际上只是广义/抽象代数,因此数学和编程之间的界限模糊了,因此说 “Haskell没有变量”虽然本质上不完全正确,但信息量不够。 - Erik Kaplun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接