List 筛选两个列表中较大的元素
我试图写一个Haskell程序,它输出一个素数列表,但只输出那些平方大于前一个素数和后一个素数乘积的素数。例如,给定List 筛选两个列表中较大的元素,list,haskell,filter,List,Haskell,Filter,我试图写一个Haskell程序,它输出一个素数列表,但只输出那些平方大于前一个素数和后一个素数乘积的素数。例如,给定 primes = [2, 3, 5, 7, 11, 13, 17] -- keep 5 since 5² > 3*7 -- keep 11 since 11² > 7*13 我的计划是创建正方形和相邻乘积的列表,然后使用过滤器只输出素数列表中正方形大于相邻乘积的元素。 这就是我目前所拥有的 products :: [Int] products = zipWith
primes = [2, 3, 5, 7, 11, 13, 17]
-- keep 5 since 5² > 3*7
-- keep 11 since 11² > 7*13
我的计划是创建正方形和相邻乘积的列表,然后使用过滤器只输出素数列表中正方形大于相邻乘积的元素。
这就是我目前所拥有的
products :: [Int]
products = zipWith (*) primes (drop 2 primes)
squares :: [Int]
squares = zipWith (*) (drop 1 primes) (drop 1 primes)
goodPrimes :: [Int]
goodPrimes = filter (\products, squares -> squares > products) (drop 1 primes)
除了goodPrimes
功能外,所有功能都正常工作。
我希望一切都很清楚,有人能帮助我。您的
goodPrimes
lambda(参数之间的逗号)中有语法错误
我们还需要将产品、正方形和素数列表的元素配对(使用zip3
)
primes::[Int]
素数=[2,3,5,7,11,13,17]
正方形::[Int]
正方形=zipWith(*)(尾部素数)(尾部素数)
产品::[Int]
产品=带(*)素数的ZIP(下降2个素数)
goodPrimes::[Int]
goodPrimes=fmap(\(prime,\,\)->prime)
$filter(\(素数,prod,square)->square>prod)
$zip3(尾部素数)产品
我们可以内联平方的计算,使goodPrimes
更干净,然后我们可以删除squares
goodPrimes::[Int]
goodPrimes=fmap-fst
$filter(\(prime,prod)->prime*prime>prod)
$zip(尾部底漆)产品
您可以进一步使用
zip3
获取包含所有三个相关值的元组;然后一个简单的列表理解将给你最终的结果
> zip3 <*> tail <*> tail.tail $ primes
[(2,3,5),(3,5,7),(5,7,11),(7,11,13),(11,13,17)]
> [ y | (x, y, z) <- zip3 <*> tail <*> tail.tail $ primes, y*y > x*z]
[5,11]
>zip3 tail.tail$primes
[(2,3,5),(3,5,7),(5,7,11),(7,11,13),(11,13,17)]
>[y |(x,y,z)x*z]
[5,11]
zip tail$primes
是一个很好的生成相邻对列表的习惯用法。我不确定zip3 tail tail.tail$primes是否也很好。明确的形式是zip3素数(尾部素数)(尾部素数))你的方向是正确的,但不是完全正确的。为了继续你的思路,我们可以写
goodPrimes = -- filter (\products, squares -> squares > products) (drop 1 primes)
map (\ (_,_,p) -> p) $
filter (\ (product, square, prime) -> square > product )
(zip3 products
squares
(drop 1 primes))
将方块、产品和素数一起包装成三份,过滤三份,然后回收素数。这被称为范例,或在远古时代
或者我们可以通过列表理解重新实现过滤器
,融合所有定义并将结果简化为
goodPrimes2 =
[ prime | ((prod, sq), prime) <- products `zip` squares `zip` drop 1 primes
, sq > prod ]
=
[ prime | ((prod, sq), prime) <-
zipWith (*) primes (drop 2 primes)
`zip` zipWith (*) (drop 1 primes) (drop 1 primes)
`zip` drop 1 primes
, sq > prod ]
=
[ p1 | ((p0, p2), p1) <-
primes `zip` (drop 2 primes) `zip` drop 1 primes
, p1*p1 > p0*p2]
=
[ p1 | (p0:p1:p2:_) <- iterate tail primes -- or (tails primes)
, p1*p1 > p0*p2]
玩弄代码,摇动代码,直到它变得简单明了,这是一件很好的事情。这一顺序可以继续下去
=
[ p1 | (p0:p1:p2:_) <- iterate tail primes -- or (tails primes)
, p1*p1 > p0*p2]
=
concatMap (\ case (p0:p1:p2:_) -> [p1 | p1*p1 > p0*p2] )
(tails primes)
=
tails primes >>= (\ case (p0:p1:p2:_) -> [p1 | p1*p1 > p0*p2] )
但是,最后这些将列表视为“单子”的变体现在可能对您不感兴趣
顺便说一句,渐进式尾部上的映射是公共Lisp中的一个原语,称为,而尾部上的concat映射(在其他语言中称为“flatmapping”)也是原语(因此在Haskell中,
mapcon f=(tails>=>f)
。欢迎使用StackOverflow。-请试着问一些具体的问题,比如“为什么我会收到这个特定的错误信息”,而不仅仅是“它不起作用,请有人帮帮我”。我可以马上说,(\products,squares->…)
是无效的语法。您可以将双参数lambda编写为(\products squares->…)
,也可以将lambda编写为单元组参数(\(products,squares)->…)
。你明白区别吗?啊,好的,看起来不错,谢谢。我对Haskell还是很陌生,所以我不知道如何正确使用过滤函数,我明白thanks@MichaWiedenmannOP的问题中没有遗漏)
。但是注意到,我在zip3
版本中添加了一个中间步骤。谢谢,这是一个很好的解决方案,我甚至理解它的工作方式!很高兴听到这个消息,不客气。:)主要的教训是,不要害怕玩它,摇动代码,直到它变成简单而美好的东西。
> take 20 primes
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71]
> take 10 goodPrimes2
[5,11,17,29,37,41,53,59,67,71]
=
[ p1 | (p0:p1:p2:_) <- iterate tail primes -- or (tails primes)
, p1*p1 > p0*p2]
=
concatMap (\ case (p0:p1:p2:_) -> [p1 | p1*p1 > p0*p2] )
(tails primes)
=
tails primes >>= (\ case (p0:p1:p2:_) -> [p1 | p1*p1 > p0*p2] )
goodPrimes3 = foo primes
where
foo = tails >=> (\ case (p0:p1:p2:_) -> [p1 | p1*p1 > p0*p2] )