如果您需要上下文,最简单的方法是使用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 而不是这个。
如果你想让事情变得简单,那就保持简单。数据声明是确保您不将数据放入数据类型中的最简单方法,除非它已经是某个类型类的成员。