Haskell:具有类限制的元素列表

时间:2012-10-19 21:41:24

标签: haskell

这是我的问题:

这完美无缺:

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'

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

提前致谢!!! =)

驿站

2 个答案:

答案 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而不是此。

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