使用Void的实际例子

时间:2016-06-24 13:13:44

标签: haskell types type-systems curry-howard

修改:按Void,我的意思是Haskell的Void类型,即空类型不能包含undefined的值。

目前正在讨论Swift Evolution是否将noreturn函数属性替换为实际的Void类型。要做到这一点,我们必须确保这将为平台带来真正的好处。使用Void作为返回类型是不够的。

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

,不要太过深入HKT,Monads,所有那些高级别的东西。标准库中的实用程序功能也是一个不好的例子。一个完美的例子是街机游戏的一部分或类似的东西。

1 个答案:

答案 0 :(得分:16)

(说到Void作为 no 值的类型,这与只有一个值的类型不同,通常称为Unit。)

在Haskell流媒体库(如streamingpipes)中,有一些数据类型代表"类型为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上这个技巧的一个例子。