空虚和荒谬是如何工作的
How do Void and absurd work
Void
的源代码状态:
newtype Void = Void Void
instance showVoid :: Show Void where
show = absurd
absurd :: forall a. Void -> a
absurd a = spin a
where
spin (Void b) = spin b
好像Void
是无限递归类型,而absurd
是无限递归函数。我在 REPL 中尝试了 运行 show ((unsafeCoerce "lol") :: Void)
,它立即进入了无限循环。
这里困扰我的是 absurd :: forall a. Void -> a
的类型签名。签名如何有效?编译器是否识别无限递归函数并允许它们具有任何 return 类型,知道它们在调用时永远不会实际终止? absurd = unsafeCoerce
不是一样的效果吗?
不,编译器不识别无限循环函数。这实际上是不可能的 - 请参阅 Halting Problem.
签名有效,因为函数体中没有任何内容可以确定(或影响)return 类型应该是什么。因此,return 类型可以是任何类型。就这么简单。
Void
的要点是它是一种根本不能有任何值的类型。就像一个空集。在这种情况下,属性 是通过使 Void
的每个值都包含另一个 Void
的巧妙技巧来实现的,因此不可能构造 Void
的值.这意味着,出于所有实际目的,类型 Void
不能有任何值。
对应的函数absurd
是永远无法调用的函数。此 属性 源自以 Void
作为参数的函数。由于不能有 Void
类型的值,因此无法为该函数提供参数,因此无法调用它。这种功能在一些非常高级的边缘情况下很有用,但主要是理论上的好奇心。
absurd
的实现并不重要,因为不可能有 Void
的值 - 无法构造它。这也是为什么拥有这样一个函数是安全的——它不是无中生有,它永远不会发生,所以它只用于类型检查器的证据。所以是的,unsafeCoerce
也可以安全使用。
但是,是的,无限递归函数可以输入为任何 return 类型,这将进行类型检查 - 它不是类型检查器中编码的特定功能,它只是从其他规则中脱离出来我们有。一种看待它的方法是,由于该函数是无限递归的,因此没有证据表明您将 return 类型描述为存在的任何内容。
Void
的源代码状态:
newtype Void = Void Void
instance showVoid :: Show Void where
show = absurd
absurd :: forall a. Void -> a
absurd a = spin a
where
spin (Void b) = spin b
好像Void
是无限递归类型,而absurd
是无限递归函数。我在 REPL 中尝试了 运行 show ((unsafeCoerce "lol") :: Void)
,它立即进入了无限循环。
这里困扰我的是 absurd :: forall a. Void -> a
的类型签名。签名如何有效?编译器是否识别无限递归函数并允许它们具有任何 return 类型,知道它们在调用时永远不会实际终止? absurd = unsafeCoerce
不是一样的效果吗?
不,编译器不识别无限循环函数。这实际上是不可能的 - 请参阅 Halting Problem.
签名有效,因为函数体中没有任何内容可以确定(或影响)return 类型应该是什么。因此,return 类型可以是任何类型。就这么简单。
Void
的要点是它是一种根本不能有任何值的类型。就像一个空集。在这种情况下,属性 是通过使 Void
的每个值都包含另一个 Void
的巧妙技巧来实现的,因此不可能构造 Void
的值.这意味着,出于所有实际目的,类型 Void
不能有任何值。
对应的函数absurd
是永远无法调用的函数。此 属性 源自以 Void
作为参数的函数。由于不能有 Void
类型的值,因此无法为该函数提供参数,因此无法调用它。这种功能在一些非常高级的边缘情况下很有用,但主要是理论上的好奇心。
absurd
的实现并不重要,因为不可能有 Void
的值 - 无法构造它。这也是为什么拥有这样一个函数是安全的——它不是无中生有,它永远不会发生,所以它只用于类型检查器的证据。所以是的,unsafeCoerce
也可以安全使用。
但是,是的,无限递归函数可以输入为任何 return 类型,这将进行类型检查 - 它不是类型检查器中编码的特定功能,它只是从其他规则中脱离出来我们有。一种看待它的方法是,由于该函数是无限递归的,因此没有证据表明您将 return 类型描述为存在的任何内容。