Haskell 是强类型编程语言吗?

Is Haskell a strongly typed programming language?

Haskell 是强类型的吗? IE。分配一个变量后是否可以更改变量的类型?我似乎无法在互联网上找到答案。

它是强类型的。请参阅此处的第 2.3 节:Why Haskell matters

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

首先,haskell 和大多数函数式编程 (FP) 语言都没有概念 "variable"。相反,他们使用 "name" 和 "value" 的概念,他们只是 "bind" 一个名称的值。一旦绑定了值,就不能再绑定同名的另一个值,这是FP的关键特性。

强类型是另一个话题。是的,haskell 是强类型的,大多数 FP 语言也是。强类型赋予 FP "type inference" 强大的能力,可以消除编译时隐藏的错误,并有助于减少源代码的大小。

也许您正在比较 haskell 和 python? Python 也是强类型的。 haskell和python的区别是"static typed"和"dynamic typed"。术语 "Strong type" 和 "Weak Type" 的实际含义含糊不清。那又是一个长篇大论了...

您似乎混淆了 dynamic/static 和 weak/strong 的输入。

动态或静态类型是关于变量的类型是否可以在执行期间更改。

弱类型或强类型是指能够仅从函数签名中预测类型错误。

Haskell 是静态类型和强类型。

但是,Haskell 中没有变量这样的东西,因此谈论动态类型或静态类型毫无意义,因为每个分配有值的标识符在执行时都无法更改。

编辑:但是正如 goldenbull 所说,那些打字概念没有明确定义。

Static — 类型在编译时已知。 Java 和 Haskell 有静态类型。还有 C/C++、C#、Go、Scala、Rust、Kotlin、Pascal 等等。

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

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

Dynamic — Python、JavaScript、Ruby、PHP、Clojure(以及一般的 Lisp), Prolog, Erlang, Groovy等也可以叫"unityped";动态类型可以在静态设置中 "emulated" ,但反之则不然,除非使用外部静态分析工具。一些语言可以混合动态和静态(参见 gradual typing, e.g. https://typedclojure.org/)。

一些语言为一个或多个模块启用静态类型,在导入时应用,例如:Python+Mypy, Typed Clojure, JavaScript+Flow, PHP+Hack 仅举几例。

Strong — 旨在被视为 Cat 的值始终是;试图像 Dog 一样对待它们会引起很大的 meeewww...我的意思是错误。

Weak — 这有效地归结为 2 个相似但不同的东西:类型强制(例如 "5"+3 等于 8 in PHP —还是这样做!)和内存重新解释(例如 C 和 C++ 中的 (int) someCharValue(bool) somePtr,但 C++ 希望您明确地说 reinterpret_cast)。所以确实存在 强制弱化重新解释弱化,并且不同的语言在这两种方式中的一种或两种方面都很弱。

有趣的是,请注意强制转换本质上是隐式的,而内存重新解释是显式的(汇编除外)——所以弱类型由隐式 显式行为组成。也许这是在弱类型下引用 2 个不同子类别的更多原因。


存在具有所有 4 种可能组合的语言,variations/gradations。

Haskell为静态+强;当然它有 unsafeCoerce 所以它有时可以是静态的+有点重新解释 - 弱,但是 unsafeCoerce 非常不受欢迎,除非在极端情况下你确定情况确实如此但可以似乎说服了编译器而没有一路倒退并以不同的方式复述整个故事。

C 是 static+weak 因为所有内存都可以自由地重新解释为它最初不打算包含的东西,因此很弱。但是所有这些重新解释都由类型检查器跟踪,因此仍然是完全静态的。但是C不做隐含的强制转换,所以它只是reinterpret-weak.

Python 是动态的+几乎完全是强 — 在执行期间到达该行之前,在任何给定的代码行上都没有已知的类型,但是存在的值在运行时确实有与之关联的类型,并且不可能重新解释内存。隐式强制转换也保持在一个有意义的最小值,所以可以说 Python 是 99.9% 强和 0.01% 强制转换弱

PHP 和 Java 脚本是动态的+主要是弱的 — 动态的,因为在你执行和反省它的内容之前没有任何类型,而且强制转换的弱点在于,强制转换一直都在发生,而且你从未真正期望被强制转换的事情,除非你只是调用方法和函数而不使用内置操作。这些胁迫是互联网上大量幽默的来源。没有内存重新解释,所以 PHP 和 JS 是 coercion-weak.


此外,有些人喜欢认为静态类型是关于具有类型的变量,而强类型是关于具有类型的值——这是理解全貌的一种非常有用的方式,但它 不完全正确:一些动态类型语言还允许 variables/parameters 用 types/constraints 注释,这是在运行时强制执行的。

在静态类型中,表达式具有类型;变量具有类型的事实只是变量被用作将较大表达式与较小表达式粘合在一起的手段的结果,因此变量本身并不是具有类型的。

同样,在动态类型中,不是变量缺少静态已知类型——而是所有的表达式!变量缺乏类型仅仅是它们存储的表达式缺乏类型的结果。


最后一张插图

在动态类型中,所有的猫、狗甚至大象(实际上是整个动物园!)都被包装在相同大小的盒子中。

在静态输入中,这些框看起来不同,并且上面贴有标签,说明里面是什么。

有些人喜欢它,因为他们可以只使用一个盒子的外形尺寸,而不必在盒子上贴任何标签——这只是盒子彼此之间的排列,隐含地(并且希望)提供输入理智。

有些人也喜欢它,因为它允许他们玩各种把戏,老虎暂时被装在闻起来像狮子的箱子里运输,熊被放在与狼或鹿相同的相互连接的箱子阵列中。

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

有了标签和关于如何处理各种标签的盒子的明确规则,automated/mechanized 逻辑推理可以用来得出物流系统不会做什么或肯定会做什么的结论(静态验证,形式证明,或者至少像 QuickCheck 一样的伪证明),物流的某些方面仍然需要通过试运行来验证,例如物流团队是否正确地找到了客户。 (集成测试、验收测试、最终用户完整性检查)。


此外,在弱打字中,狗可以被分割并重新组装成弗兰肯斯坦猫。他们喜不喜欢,结果丑不丑。 (弱类型)

但是如果你给盒子加上标签,把弗兰肯斯坦猫放在猫盒子里仍然很重要。 (静态+弱类型)


在强类型中,虽然你可以把猫放在狗的盒子里,但你只能一直假装它是狗,直到你试图通过喂它只有狗才会吃的东西来羞辱它——如果发生这种情况,它会大声尖叫,但在那之前,如果你在动态类型中,它会默默地接受它的位置(在静态世界中,它会拒绝在你说 "kitty" 之前被放在狗的盒子里) .