【发布时间】:2018-05-27 01:34:05
【问题描述】:
我可以在 Haskell 中有一个类型安全的联合(如 C 的 union)吗?这是我试过的最好的,这里是Variant,以C++的std::variant命名:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Emulation.CPlusPlus.Variant (
Variant, singleton
) where
import Data.Type.Bool
import Data.Type.Equality
import Type.Reflection
data Variant :: [*] -> * where
Singleton :: a -> Variant (a ': as)
Arbitrary :: Variant as -> Variant (a ': as)
singleton :: (Not (bs == '[]) || a == b) ~ 'True => forall a b. a -> Variant (b ': bs)
singleton x = case eqTypeRep (typeRep :: TypeRep a) (typeRep :: TypeRep b) of
Nothing -> Arbitrary (singleton x)
Just HRefl -> Singleton x
这会产生如下错误消息:
Prelude> :load Variant.hs
[1 of 1] Compiling Emulation.CPlusPlus.Variant ( Variant.hs, interpreted )
Variant.hs:19:14: error:
• Could not deduce: (Not (bs == '[]) || (a0 == b0)) ~ 'True
from the context: (Not (bs == '[]) || (a == b)) ~ 'True
bound by the type signature for:
singleton :: forall (bs :: [*]) a b.
((Not (bs == '[]) || (a == b)) ~ 'True) =>
forall a1 b1. a1 -> Variant (b1 : bs)
at Variant.hs:19:14-85
The type variables ‘a0’, ‘b0’ are ambiguous
• In the ambiguity check for ‘singleton’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature:
singleton :: (Not (bs == '[]) || a == b) ~ True =>
forall a b. a -> Variant (b : bs)
|
19 | singleton :: (Not (bs == '[]) || a == b) ~ True => forall a b. a -> Variant (b ': bs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
我不明白这种歧义是如何出现的。
【问题讨论】:
-
你的
forall a b在(Not (bs == '[]) || a == b)的右边,所以你在a -> Variant (b ': bs)中提到的a和b独立于约束中的a和b.也就是说,GHC 读取它的方式与singleton :: (Not (bs == '[]) || a == b) ~ 'True => forall x y. x -> Variant (y ': bs)相同
标签: haskell reflection unions gadt data-kinds