所以我正在玩这个:
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)
我不知道为什么.
这与多态类型的真正含义有关,它比它们首次出现时稍微复杂一些.
在这一点上可能更容易转换思维方式,并在量词看作为是一种形式拉姆达抽象: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,并且投影函数在(现在是单态的)模式匹配之后简单地丢弃其他三个.