这是我的问题:
这完美无缺:
type Asdf = [Integer]
type ListOfAsdf = [Asdf]
现在我想做同样的但是使用Integral类限制:
type Asdf2 a = (Integral a) => [a]
type ListOfAsdf2 = (Integral a) => [Asdf2 a]
我收到了这个错误:
Illegal polymorphic or qualified type: Asdf2 a
Perhaps you intended to use -XImpredicativeTypes
In the type synonym declaration for `ListOfAsdf2'
我已经尝试了很多东西,但是我仍然无法创建具有上述类限制的类型。
提前致谢!!! =)
驿站
答案 0 :(得分:5)
反对反Existentionallists
我总是不喜欢Haskell中的反存在型谈话,因为我经常发现存在有用。例如,在一些快速检查测试中,我的代码类似于(具有讽刺意味的未经测试的代码):
data TestOp = forall a. Testable a => T String a
tests :: [TestOp]
tests = [T "propOne:" someProp1
,T "propTwo:" someProp2
]
runTests = mapM runTest tests
runTest (T s a) = putStr s >> quickCheck a
即使在某些生产代码的一角,我发现制作一个类型列表很方便,我需要随机值:
type R a = Gen -> (a,Gen)
data RGen = forall a. (Serialize a, Random a) => RGen (R a)
list = [(b1, str1, random :: RGen (random :: R Type1))
,(b2, str2, random :: RGen (random :: R Type2))
]
回答您的问题
{-# LANGUAGE ExistentialQuantification #-}
data SomeWrapper = forall a. Integral a => SW a
答案 1 :(得分:5)
如果您需要上下文,最简单的方法是使用data
声明:
data (Integral a) => IntegralData a = ID [a]
type ListOfIntegralData a = [IntegralData a]
*Main> :t [ ID [1234,1234]]
[ID [1234,1234]] :: Integral a => [IntegralData a]
这具有确保将Integral
上下文添加到使用IntegralData
数据类型的每个函数的(唯一)效果。
sumID :: Integral a => IntegralData a -> a
sumID (ID xs) = sum xs
type
同义词不适合您的主要原因是类型同义词被设计为
就是这样 - 取代类型,而不是类型签名。
但是如果你想要存在,最好的方法是使用GADT,因为它会为你处理所有的量化问题:
{-# LANGUAGE GADTs #-}
data IntegralGADT where
IG :: Integral a => [a] -> IntegralGADT
type ListOfIG = [ IntegralGADT ]
因为这实际上是一种存在主义类型,所以你可以将它们混合起来:
*Main> :t [IG [1,1,1::Int], IG [234,234::Integer]]
[IG [1,1,1::Int],IG [234,234::Integer]] :: [ IntegralGADT ]
根据您的申请,您可能会觉得非常方便。
GADT相对于数据声明的主要优点是,当您模式匹配时,您隐式获得Integral
上下文:
showPointZero :: IntegralGADT -> String
showPointZero (IG xs) = show $ (map fromIntegral xs :: [Double])
*Main> showPointZero (IG [1,2,3])
"[1.0,2.0,3.0]"
但存在量化有时会被用于错误的原因, (例如,想要将所有数据混合在一个列表中,因为这就是你所拥有的 习惯于动态类型语言,你还没有习惯 静态类型及其优点)。
除非你需要混合不同,否则我觉得这比它的价值更麻烦 积分类型在一起而不转换它们。我看不出原因 为什么这会有所帮助,因为你在使用它们时必须转换它们。
例如,您无法定义
unIG (IG xs) = xs
因为它甚至没有打字检查。经验法则:你不能做那些在右侧提到a
类型的东西。
但是,这没关系,因为我们转换了类型a
:
unIG :: Num b => IntegralGADT -> [b]
unIG (IG xs) = map fromIntegral xs
当我认为您的原始计划不必要时,存在量化已迫使您转换数据! 您也可以将所有内容转换为Integer而不是此。
如果您想要简单的事情,请保持简单。数据声明是确保您不将数据放入数据类型的最简单方法,除非它已经是某个类型类的成员。