获取型积分一个的值=>并[a]从一个积分的值=>([A],[A],[A])
所以我玩这个周围:获取型积分一个的值=>并[a]从一个积分的值=>([A],[A],[A])
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
,我宁愿有三个值:abundants
,perfects
和deficients
所有类型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)
。
这似乎足够的cromulent。
现在我知道我可以单独执行这些(只是perfects = filter isPerfect [1..]
),或将其约束到所有相同类型的((abundants,perfects,deficients) = abundants_perfects_deficients
工作正常,如果abundants,perfects,deficients :: [Integer]
),但
- 我喜欢使用共享信息来建立所有三个
- 我想不只是被限制为
Integer
小号
想法?
编辑:让人着迷足够的这个作品:
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'
我不知道为什么。
这涉及到多态类型的真正含义是什么,这是稍微比他们第一次的显示更加复杂。
在这一点上可能更容易转换思维方式,并在量词看成是拉姆达抽象形式:像∀ a. [a]
A型是这样一个功能采取单一类型的参数,并返回一个列表这种类型的东西。像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
,并且投影函数在(现在是单形的)模式匹配之后简单地丢弃其他三个。
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
fromIntegral
可能是有用的:
Prelude> :t fromIntegral
fromIntegral :: (Num b, Integral a) => a -> b
可能略有偏差,但无论如何。
你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
哎呦:)也是好主意。 – rampion
将无法正常工作:'FST ::(A,B) - >一个'(和snd类似),你将不得不提供一些新的三元组访问器;) –
Ops,你是对的。更新以修复它。 – nulvinge
需要删除你的(。)运算符(abundants_perfects_deficients不是函数) – rampion