unsafeVacuous
中的{p> Data.Void.Unsafe
以及.#
中的#.
和Data.Profunctor.Unsafe
都警告使用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
实例。有例子吗?特别是,如果仅使用他们的公共API进行操作,是否有可能构建遵循functor / profunctor法则的有用的那些,但面对这些不安全的函数会破坏可怕的?
答案 0 :(得分:4)
我不相信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
。