修改:按Void
,我的意思是Haskell的Void
类型,即空类型不能包含undefined
的值。
目前正在讨论Swift Evolution是否将noreturn
函数属性替换为实际的Void
类型。要做到这一点,我们必须确保这将为平台带来真正的好处。使用Void
作为返回类型是不够的。
因此,我要求您提供非常实用的示例,其中Void
的使用为代码增加了清晰度,简洁性和通用性。也许它会使用类(在Haskell意义上),也许是泛型,也许它会在ADT中包含Void
。
但请,不要太过深入HKT,Monads,所有那些高级别的东西。标准库中的实用程序功能也是一个不好的例子。一个完美的例子是街机游戏的一部分或类似的东西。
答案 0 :(得分:16)
(说到Void
作为 no 值的类型,这与只有一个值的类型不同,通常称为Unit。)
在Haskell流媒体库(如streaming或pipes)中,有一些数据类型代表"类型为a
的值的来源,一旦用完,就返回一个值输入r
"。像Producer a m r
这样的东西(m
是基础monad,但这里不相关。)
让生成器返回一个值(与运行时它们发出的值类型无关的类型)实际上非常有用。例如,您可以定义一个"流分割器"作为类型的函数:
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)
如果我们要为永不失败的函数takesACallback
定义a -> IO r
版本,该怎么办?进入和离开Either
是一件麻烦事,并且在获得价值时会产生虚假的模式匹配。
使用Void
我们可以先将a -> IO r
转换为a -> IO (Either Void r)
,然后将其传递给takesACallback
,然后删除"假的&#34}。使用absurd :: Void -> a
函数的错误分支。
takesACallback':: (a -> IO r) -> a -> IO r
takesACallback' callback = fmap (either absurd id)
. takesACallback (fmap Right . callback)
Here是Hackage上这个技巧的一个例子。