从Integral a =>([a],[a],[a])的值中获取Integral a => [a]类型的值

ram*_*ion 6 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)
Run Code Online (Sandbox Code Playgroud)

虽然我有abundants_perfects_deficients,我宁愿有三个值:abundants,perfects,和deficients所有类型的Integral a -> [a].

有一件事是行不通的:

abundants,perfects,deficients :: Integral a => [a] 
(abundants,perfects,deficients) = abundants_perfects_deficients
Run Code Online (Sandbox Code Playgroud)

因为这限制了三者都是一样的a.

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

perfects :: Integral a => [a] 
(_,perfects,_) = abundants_perfects_deficients
Run Code Online (Sandbox Code Playgroud)

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

这似乎足够了.

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

  • 我喜欢使用共享信息来构建这三个
  • 我想不只是被限制在Integers

想法?


编辑:这非常有用:

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

但这不是:

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'
Run Code Online (Sandbox Code Playgroud)

我不知道为什么.

C. *_*ann 7

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

在这一点上可能更容易转换思维方式,并在量词看作为是一种形式拉姆达抽象:A型喜欢的? a. [a]是这样一个函数采取单一类型的参数,并返回该类型的事情的清单.类约束Integral a可以看作是GHC为您找到值时隐式提供的附加参数(特别是实例字典).

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

写这样,abundants_perfects_deficientsis 的类型/\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]).这需要ImpredicativeTypes扩展,其中有一个有点波折历史,以及我仍需警惕.

你在这里绊倒的很多东西是GHC不够聪明,无法找出"明显"的东西,比如基于仅在绑定的特定部分中使用的浮动隐式类型和约束参数.鉴于它在幕后已经有多大的魔力,这并没有太多困扰我.:]

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