什么时候 unsafeVacuous、#. 和 .# 不安全?
Just when are unsafeVacuous, #., and .# unsafe?
Data.Void.Unsafe
中的 unsafeVacuous
和 Data.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
。
Data.Void.Unsafe
中的 unsafeVacuous
和 Data.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
。