使用 Void 的实际例子

Posted

技术标签:

【中文标题】使用 Void 的实际例子【英文标题】:Practical examples of using Void 【发布时间】:2016-10-27 03:05:37 【问题描述】:

编辑:Void,我的意思是 Haskell 的 Void 类型,即不能有值但 undefined 的空类型。

关于 Swift Evolution 是否将 noreturn 函数属性替换为实际的 Void 类型正在进行讨论。为此,我们必须确保这将为平台带来真正的好处。使用Void 作为返回类型是不够的。

所以我要求您提供非常实用的示例,其中Void 的使用增加了代码的清晰度、简洁性和通用性。也许它会使用类(在 Haskell 意义上),也许是泛型,也许它会将 Void 合并到 ADT 中。

但是拜托,不要对 HKT、Monads 和所有高级别的东西走得太远。标准库中的实用函数也是一个不好的例子。一个完美的例子是街机游戏或类似游戏的一部分。

【问题讨论】:

您说的是只有一个值的 unit 类型(mod. undefined)还是真正的 void 类型(除了通常的 undefined 之外没有其他值)? Void 没有居民,你怎么能返回 Void 类型的东西。 @pdexter 很多语言都使用 void 作为单元类型(C、Java、...)的特殊替代品 好吧,我认为这不会得到任何合适的答案 - 我建议您访问 haskell IRC 或 reddit 频道 另见***.com/questions/11968789 【参考方案1】:

(说Voidno值的类型,不同于只有一个值的类型,通常称为Unit。)

在 streaming 或 pipes 等 Haskell 流式库中,有一些数据类型表示“a 类型的值的来源,一旦用尽,就会返回 r 类型的值”。 Producer a m r 之类的东西(m 是一个基本单子,但在这里不相关。)

让生产者返回一个值(与他们在运行时发出的值类型无关的类型)实际上非常有用。例如,您可以将“流式拆分器”定义为具有以下类型的函数:

streamingSplit :: Producer a m r -> Producer a m (Producer a m r)

此函数对生产者进行分段,而无需在内存中累积拆分之前的所有元素。

现在,如果我们想在类型级别表达生产者从不停止生产东西怎么办?我们可以让它返回一个Void类型的值,比如Producer a m Void

另一个可能的用例。假设您有一个接受可能失败的回调的高阶函数。比如:

-- does something with the wrapped callback, maybe emit a log message or whatever
takesACallback :: (a -> IO (Either e r)) -> a -> IO (Either e r)

如果我们想为函数a -> IO r 定义一个永不失败takesACallback 版本怎么办?进出Either 很麻烦,并且在取出值时会导致虚假的模式匹配。

使用Void,我们可以首先将a -> IO r 转换为a -> IO (Either Void r),将其传递给takesACallback,然后使用absurd :: Void -> a 函数删除Either 上的“假”错误分支。

takesACallback':: (a -> IO r) -> a -> IO r
takesACallback' callback = fmap (either absurd id) 
                         . takesACallback (fmap Right . callback) 

Here 是 Hackage 这个技巧的一个例子。

【讨论】:

谢谢,这真的很有帮助!无法投票,但已接受。 @Anton3 生产者不会停止的另一种说法是让返回类型保持多态(它可以是任何类型,因为它从未真正返回过)。 这仅仅是因为多态(独立)返回类型与 Void 同构。

以上是关于使用 Void 的实际例子的主要内容,如果未能解决你的问题,请参考以下文章

C语言多线程的一个简单例子

synchronized实际中例子

Java Function & Supplier 的实际例子对比感受抽象和懒加载

在 Scala 中使用符号的实际例子?

Appium - 我们啥时候使用触摸动作?我可以有实际的例子来输入文本吗?

C 语言restrict 关键字的概念及使用例子