如果一个函数的返回类型为⊥(bottom type),则表示它永不返回。例如,在相当普通的情况下,它都可以退出或抛出。
据推测,如果函数的参数类型为⊥,则永远不会(安全)调用它。是否有任何理由定义这种功能?
如果一个函数的返回类型为⊥(bottom type),则表示它永不返回。例如,在相当普通的情况下,它都可以退出或抛出。
据推测,如果函数的参数类型为⊥,则永远不会(安全)调用它。是否有任何理由定义这种功能?
Answers:
其中一个的定义性质的或空类型是存在的函数对于每一种类型的。实际上,存在这样的独特功能。因此,将此功能作为标准库的一部分提供是相当合理的。通常它被称为absurd。(在具有子类型系统中,这可能是简单地通过具有处理是每一种类型的子类型。然后,将隐式转换absurd。另一个相关的方法是限定 为,其可以简单地被实例化的任何类型的)。
您绝对希望拥有这样的功能或等效功能,因为这是使您能够利用产生的功能的原因。例如,让我们说,我给一笔型。我对此进行了案例分析,在案例中,我将使用抛出一个异常:E → ⊥。在情况下,我将使用。总的来说,我想类型的值,所以我需要做一些事来把一个成。那就是absurd让我做的。
就是说,没有太多理由来定义您自己的的函数。根据定义,它们必然是的实例absurd。不过,如果absurd标准库未提供它,或者您希望使用类型专用的版本来辅助类型检查/推断,则可以这样做。但是,您可以轻松生成最终实例化为的类型的函数。
即使没有太多理由要编写这样的函数,也通常应该允许它。原因之一是它简化了代码生成工具/宏。
absurdabsurdthrow
为了补充对函数的描述,absurd: ⊥ -> a我有一个具体示例说明该函数实际上有用的地方。
考虑Haskell数据类型Free f a,该数据类型表示具有- f形节点和包含as的叶子的常规树结构 :
data Free f a = Op (f (Free f a)) | Var a
可以使用以下功能折叠这些树:
fold :: Functor f => (a -> b) -> (f b -> b) -> Free f a -> b
fold gen alg (Var x) = gen x
fold gen alg (Op x) = alg (fmap (fold gen alg) x)
简而言之,此操作alg位于节点和gen叶子处。
到现在为止:可以使用定点数据类型表示所有递归数据结构。在Haskell中Fix f,可以将其定义为type Fix f = Free f ⊥(即,具有- f形节点且在函子外部没有叶子的树f)。传统上,此结构也有一个折叠,称为cata:
cata :: Functor f => (f a -> a) -> Fix f -> a
cata alg x = fold absurd alg x
这很好地使用了荒唐的东西:由于树上没有叶子(因为⊥除了以外没有其他居民undefined),所以永远不可能使用genfold来absurd说明这一点!
底部类型是所有其他类型的子类型,在实践中可能非常有用。例如,类型NULL在C理论类型安全的版本必须是所有其他指针类型的子类型,否则你无法归还,例如NULL其中char*预期; 同样,undefined理论上类型安全的JavaScript的类型必须是该语言中所有其他类型的子类型。
exit()throw()IntIntexit()
NULL是不是单位类型,不同于⊥是空类型?
void*,则需要为它指定一个可以用于任何指针类型的特定类型。
我可以想到一种用途,并且它被认为是对Swift编程语言的一种改进。
斯威夫特有一个maybeMonad,拼写为Optional<T>或T?。有很多与之交互的方法。
您可以使用条件展开
if let nonOptional = someOptional {
print(nonOptional)
}
else {
print("someOptional was nil")
}
您可以使用map,flatMap以变换值
!,类型(T?) -> T)强制解开内容,否则触发崩溃nil-coalescing运算符(??,类型的(T?, T) -> T)取其值,否则使用默认值:
let someI = Optional(100)
print(someI ?? 123) => 100 // "left operand is non-nil, unwrap it.
let noneI: Int? = nil
print(noneI ?? 123) // => 123 // left operand is nil, take right operand, acts like a "default" value
不幸的是,没有简洁的方式说“解开或抛出错误”或“解开或因自定义错误消息而崩溃”。就像是
let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")
不会编译,因为fatalError具有类型() -> Never(()是VoidSwift的单位类型,Never是Swift的底部类型)。调用它会产生Never,与T预期的正确操作数不兼容??。
为了解决这个问题,Swift Evolution提案SE-0217-提出了“ 解开或死亡”运算符。它最终被拒绝了,但引起了人们的兴趣,希望成为Never所有类型的子类型。
如果Never被设为所有类型的子类型,那么前面的示例将是可编译的:
let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")
因为的呼叫站点??具有类型(T?, Never) -> T,它将与的(T?, T) -> T签名兼容??。
Swift具有“ Never”类型,这似乎与底部类型非常相似:声明为返回Never的函数永远不会返回,带有Never类型的参数的函数永远不会被调用。
这在协议中很有用,协议可能由于语言的类型系统而受到限制,即一个类必须具有某种功能,但不要求必须调用此函数,也不要求参数的类型将是。
有关详细信息,请查看swift-evolution邮件列表中的较新文章。
(x ? 3 : throw new Exception())出于分析目的,类似的东西会被替换成类似的东西(x ? 3 : absurd(throw new Exception()))?