什么时候 unsafeVacuous、#. 和 .# 不安全?

Just when are unsafeVacuous, #., and .# unsafe?

Data.Void.Unsafe 中的

unsafeVacuousData.Profunctor.Unsafe 中的 .##. 都警告将这些函数与 functors/profunctors 一起使用的危险是 GADT。一些危险的例子是显而易见的:

data Foo a where
  P :: a -> Foo a
  Q :: Foo Void

instance Functor Foo where
  fmap f (P x) = P (f x)
  fmap f Q = P (f undefined)

在这里,unsafeVacuous Q 将生成一个 Q 具有伪造类型的构造函数。

这个例子不是很麻烦,因为它看起来一点也不像一个合理的 Functor 实例。有这样的例子吗?特别是,是否有可能构建有用的函数,这些函数在仅使用 public API 进行操作时遵守 functor/profunctor 定律,但在面对这些不安全的函数时会严重崩溃?

我不相信 unsafeVacuous 会导致任何真正的函子出现问题。但是如果你写错了 Functor 你可以自己写 unsafeCoerce,这意味着它应该被标记为 {-# LANGUAGE Unsafe #-}。有 an issue about it in void.

这是我想出的 unsafeCoerce

{-# LANGUAGE GADTs               #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies        #-}
import Data.Void
import Data.Void.Unsafe

type family F a b where
  F a Void = a
  F a b    = b

data Foo a b where
  Foo :: F a b -> Foo a b

instance Functor (Foo a) where
  fmap = undefined

unsafeCoerce :: forall a b. (F a b ~ b) => a -> b
unsafeCoerce a = (\(Foo b) -> b) $ (unsafeVacuous (Foo a :: Foo a Void) :: Foo a b)

main :: IO ()
main = print $ (unsafeCoerce 'a' :: Int)

打印 97