如何在unsafeVacuous上创建一个正确的多态Functor实例失败?

时间:2013-07-19 08:35:37

标签: haskell functor gadt bottom-type

在Haskell Libraries邮件列表上讨论Void时,有this remark

  

在过去的那一天,它曾由unsafeCoerce执行   Conor McBride谁不想为遍历整个Functor付出代价   并且当类型告诉我们它不应该有时,替换它的内容   任何。如果应用于适当的Functor,这是正确的,但在   存在GADT。

unsafeVacuous的文档也说:

  

如果Void无人居住,那么只保留Functor类型值的任何Void都没有值。

     

这对于有效仿函数只能对参数执行类似GADT的分析。

这样一个淘气的GADT Functor实例怎么样? (当然只使用总函数,没有undefinederror等。)

1 个答案:

答案 0 :(得分:4)

如果您愿意提供一个不符合仿函数法律的Functor实例,那当然是可能的(但总计):

{-# LANGUAGE GADTs, KindSignatures #-}

import Data.Void
import Data.Void.Unsafe

data F :: * -> * where
  C :: F Void
  D :: F a

instance Functor F where
  fmap f _ = D

wrong :: ()
wrong = case (unsafeVacuous C :: F Int) of D -> ()

现在评估wrong会导致运行时异常,即使类型检查器将其视为总计。

修改

因为关于functoriality的讨论太多了,所以让我添加一个非正式的论证,为什么实际对其论证进行分析的GADT不能成为一个仿函数。如果我们有

data F :: * -> * where
  C :: ... -> F Something
  ...

其中Something是任何不是普通变量的类型,我们无法为Functor提供有效的F实例。 fmap函数必须将C映射到C才能遵守仿函数的身份法。但我们必须为未知F b生成b。如果Something不是普通变量,那么这是不可能的。