使用 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】:(说Void
是no值的类型,不同于只有一个值的类型,通常称为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 的实际例子的主要内容,如果未能解决你的问题,请参考以下文章
Java Function & Supplier 的实际例子对比感受抽象和懒加载