5

这是我的问题:

这完美地工作:

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'

我已经尝试了很多东西,但我仍然无法创建具有上述类限制的类型。

提前致谢!!!=)

达克

4

2 回答 2

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]"

但是存在量化有时被用于错误的原因,(例如,想要将所有数据混合在一个列表中,因为这是你习惯于动态类型语言的内容,而且你还没有习惯静态类型及其优势)。

在这里,我认为麻烦大于价值,除非您需要将不同的 Integral 类型混合在一起而不进行转换。我看不出这会有所帮助的原因,因为您在使用它们时必须转换它们。

例如,您不能定义

unIG (IG xs) = xs

因为它甚至没有类型检查。经验法则:你不能做提到a右侧类型的事情。

但是,这没关系,因为我们转换了类型a

unIG :: Num b => IntegralGADT -> [b]
unIG (IG xs) = map fromIntegral xs

当我认为您的原始计划不必这样做时,存在量化迫使您转换数据!您也可以将所有内容都转换为 Integer 而不是这个。

如果你想让事情变得简单,那就保持简单。数据声明是确保您不将数据放入数据类型中的最简单方法,除非它已经是某个类型类的成员。

于 2012-10-20T09:06:40.203 回答
5

反对反存在主义者

我总是不喜欢 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
于 2012-10-20T04:56:23.867 回答