繁体   English   中英

防止类型统一

[英]Preventing types from unifying

给出这个整数的包装:

newtype MyProxy a = MyProxy Int

mkProxy :: Int -> MyProxy a
mkProxy a = MyProxy a

addProxy :: MyProxy a -> MyProxy a -> MyProxy  a
addProxy (MyProxy a1) (MyProxy a2) = MyProxy $ a1+a2

我可以执行以下操作:

a = mkProxy 1
b = mkProxy 2
c = addProxy a b

因为幻象参数将统一。 但是我想阻止这种统一并在c行引起类型错误。

ST monad使用rank2类型来实现类似的效果。 我可以通过改变addProxy的类型来做类似的addProxy 但我特别不想这样做。 我想以某种方式注释a类型变量,以防止它在addProxy调用上统一。

这在Haskell有可能吗? 这样的选择会有危险吗?


编辑:

让我详细说明一个部分解决方案(需要-XScopedTypeVariables )。 我可以将上面的代码重写为:

c :: forall a1 a2. MyProxy a1
c = addProxy a b
    where
        a = mkProxy 1 :: MyProxy a1
        b = mkProxy 2 :: MyProxy a2

这正确地导致c上的类型错误,因为a1a2无法统一。 但这有两个缺点: ab不能在顶层定义; 并且您必须明确指定mkProxy的结果类型。

是否有可能解决这些缺点?

不,你不能,至少在没有为mkProxy指定更多mkProxy

ST monad工作的方式是要求转义计算生成类型的东西forall s. ST sa forall s. ST sa阻止sa中自由出现。

但是,在你的情况下,你正在做两个相同的计算,因此为每个计算生成一个不同的类型可以用来做邪恶的事情。 例如,如果mkInt 1每次调用时生成不同的类型,

class Evil a b c | a, b -> c where
  foo :: a -> b -> c

let x = mkProxy 1 in foo x x

会有所不同

 foo (mkProxy 1) (mkProxy 1)

我们在代码中丢失了一些非常好的属性。

然而,我们可以做一些额外的腿部工作,并使事实ab不能明确统一

 {-# LANGUAGE DataKinds #-}

 data Nat = S Nat | Z
 data Proxy (n :: Nat) a = Proxy a

 based :: a -> Proxy Z a
 based = Proxy

 fresh :: Proxy n a -> a -> Proxy (S n) a
 fresh (Proxy _) a = Proxy a

所以现在你需要做类似的事情

a = based 1

b = fresh a 2

我认为存在类型变量适合于此。 基本上,独立创建的两个存在类型变量不会统一。 在下面的test未能进行类型test ,因为它无法统一两个MyProxy的类型变量。

{-# LANGUAGE ExistentialQuantification #-}

newtype MyProxy a = MyProxy Int

data Exists f = forall a. Exists (f a)

mkProxy :: Int -> Exists MyProxy
mkProxy a = Exists (MyProxy a)

addProxy :: MyProxy a -> MyProxy a -> MyProxy a
addProxy (MyProxy a1) (MyProxy a2) = MyProxy $ a1+a2

test :: Exists MyProxy -> Exists MyProxy -> Exists MyProxy
test (Exists a) (Exists b) = Exists (addProxy a b)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM