获得Integral a =>类型的值[a]来自积分a =>的值。 ([A],[A],[A])

时间:2011-09-19 15:37:32

标签: haskell

所以我正在玩这个:

factors :: Integral a => a -> [a] 
factors n = filter (\d -> n `rem` d == 0) . takeWhile (\d -> d*d <= n) $ [ 1 .. ]

abundants_perfects_deficients :: Integral a => ([a],[a],[a])
abundants_perfects_deficients = foldr switch ([],[],[]) [1..]
  where switch :: Integral a => a -> ([a],[a],[a]) -> ([a],[a],[a])
        switch n (as,ps,ds) = 
          let t = sum (factors n) in
                if t < n  then  (as,ps,n:ds) 
          else  if t == n then  (as,n:ps,ds) 
          else                  (n:as,ps,ds)

虽然我有abundants_perfects_deficients,但我宁愿有三个值:abundantsperfectsdeficients所有类型Integral a -> [a]

有一件事不起作用:

abundants,perfects,deficients :: Integral a => [a] 
(abundants,perfects,deficients) = abundants_perfects_deficients

因为这会将三者限制在同一个a

我尝试过一个一个一个地做的事情,所以他们不会相互制约,但这也不起作用:

perfects :: Integral a => [a] 
(_,perfects,_) = abundants_perfects_deficients

因为编译器无法弄清楚如何将forall a. Integral a => ([a],[a],[a])类型的值转换为类型(t1, forall a. Integral a => [a], t2)

这似乎足够了。

现在我知道我可以单独实现它们(仅perfects = filter isPerfect [1..]),或者将它们限制为所有类型相同((abundants,perfects,deficients) = abundants_perfects_deficients如果abundants,perfects,deficients :: [Integer]可以正常工作),但是

  • 我喜欢使用共享信息构建所有三个
  • 我希望不仅限于Integer s

想法?


编辑:这非常有用:

abundants :: Integral a => [a]
abundants = f as
  where as :: [Integer]
        (as,_,_) = abundants_perfects_deficients
        f :: Integral a => [Integer] -> [a]
        f = map fromInteger

但这不是:

abundants_perfects_deficients' :: (Integral a,Integral p, Integral d) => ([a],[p],[d])
abundants_perfects_deficients' = (f as, f ps, f ds)
  where as,ps,ds :: [Integer]
        (as,ps,ds) = abundants_perfects_deficients
        f :: Integral a => [Integer] -> [a]
        f = map fromInteger

abundants,perfects,deficients :: (Integral a) => [a]
(abundants,perfects,deficients) = abundants_perfects_deficients'

我不知道为什么。

4 个答案:

答案 0 :(得分:7)

这与多态类型的真正含义有关,它比它们最初出现时稍微复杂一些。

此时,切换思维模式并将量词视为 lambda抽象的形式可能更容易:类似∀ a. [a]的类型因此是函数< / em>获取单个类型参数,并返回该类型的事物列表。像Integral a这样的类约束可以看作是GHC为您找到值时隐式提供的附加参数(特别是实例字典)。

为了强调这一点,我将把量词写为/\ a ->来模仿lambda语法,并将类约束写为常规参数。

以这种方式编写,abundants_perfects_deficients的类型为/\a -> Integral a -> ([a],[a],[a]),并且您的初始尝试失败主要是因为您尝试对双参数函数的结果进行模式匹配。在许多情况下,GHC自动地将这些隐含的参数混乱以使事情变得有效,但在这里显然不能 - 从abundants_perfects_deficients得到任何结果你首先需要将它应用于两个参数,得到一个单态结果,然后使用该模式绑定。即使模式只绑定一个值,其余为_,GHC仍然需要对模式绑定本身进行类型检查,所以即使看起来额外的参数可以浮动到单个绑定标识符,失败的原因与同时绑定所有三个一样。

要使用模式绑定三个多态值,您需要将额外的参数放在内部,为abundants_perfects_deficients提供类似(/\a -> Integral a -> [a], /\a -> Integral a -> [a], /\a -> Integral a -> [a])的类型。这需要the ImpredicativeTypes extension,其过去有点格格不入,我仍然对此保持警惕。

很多在这里绊倒你的是GHC并不聪明地弄清楚“明显”的东西,比如基于仅在绑定的特定部分中使用的浮动隐式类型和约束参数。鉴于它在幕后已经有多大的魔力,这并没有太多困扰我。 :

最简单的解决方案是分别绑定所有三个,使用选择函数来提取单个元素。这使得顶级绑定在预期的方式中具有多态性,其接收的隐式参数隐式传递给abundants_perfects_deficients,并且投影函数在(现在是单态的)模式匹配之后简单地丢弃其他三个。

答案 1 :(得分:3)

abundants,perfects,deficients :: Integral a => [a] 
(abundants,perfects,deficients) = abundants_perfects_deficients

尝试:

fst3 (a,_,_) = a
snd3 (_,a,_) = a
thd3 (_,_,a) = a

abundants,perfects,deficients :: Integral a => [a] 
abundants  = fst3 . abundants_perfects_deficients
perfects   = snd3 . abundants_perfects_deficients
deficients = thd3 . abundants_perfects_deficients

答案 2 :(得分:1)

fromIntegral可能有用:

Prelude> :t fromIntegral
fromIntegral :: (Num b, Integral a) => a -> b

答案 3 :(得分:1)

可能有点偏离主题,但无论如何。

您的factors功能有误(尝试计算factors 28;)

这是解决问题的另一种方法:

classifieds = map (\n -> (n, compare n (sum $ factors n))) [1..]

perfects = map fst $ filter ((== EQ) . snd) classifieds
abundants = map fst $ filter ((== GT) . snd) classifieds
deficients = map fst $ filter ((== LT) . snd) classifieds