Haskell 代码中嵌套列表理解错误
我正在尝试用 Haskell 编写以下列表理解,但它不会进行类型检查。我对此很陌生,无法真正弄清楚为什么。
something :: Int -> [Int]
something n = [[ 2 * x + 1 | x <- xs]|xs <- [3..n],i <- [1..],j <-[1..] ,xs == i+j+2*i*j,i<=j,i>=1]
这是我所看到的:
Couldn't match expected type `Int' with actual type `[t0]'
In the expression: [2 * x + 1 | x <- xs]
注意:这段代码可能还有更多错误。
这就是我真正想学习做的事情。从 3 到 n(这是函数的 Int 输入)的所有自然数列表中,我只想提取可以写为 i+j+2*i*j 的数字子集,其中 i, j 是整数并且i≤j且i≥1。对于这个子集列表,我想将函数 2*x+1 应用于每个元素 x 并输出最终列表。
希望这是有道理的。
I am trying to write the following list comprehension in Haskell and it doesn't typecheck. I am new at this and can't really figure out why.
something :: Int -> [Int]
something n = [[ 2 * x + 1 | x <- xs]|xs <- [3..n],i <- [1..],j <-[1..] ,xs == i+j+2*i*j,i<=j,i>=1]
This is what I see:
Couldn't match expected type `Int' with actual type `[t0]'
In the expression: [2 * x + 1 | x <- xs]
NB: There could be a lot more wrong with this piece of code.
Here's what I am really trying to learn to do. From a list of all naturals from 3 to n(which is the Int input to the function), I want to extract just the subset of numbers which can be written as i+j+2*i*j where i, j are integers and the i<=j and i>=1. To this subset list , I want to apply the function 2*x+1 to each element x and output a final list.
Hope that makes sense.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,您有一个嵌套列表理解,因此您正在创建一个列表列表,因此返回类型应该是
[[Int]]
(整数列表列表)而不是[Int]
(整数列表)。其次,
xs
是一个数字(因为您将其从数字列表中取出),但它的名称表明它是一个列表,当您执行x <- xs
时> 你实际上把它当作一个列表来对待。回应您的编辑:我真的不明白为什么您认为您需要嵌套列表理解。如果我们只是从代码中删除嵌套,我们会得到非常接近工作的结果(我还将
xs
重命名为x
因为调用了一个数字xs
只是令人困惑 - 我还删除了i
至少为 1 的条件,因为自从您从列表中获取
):i
以来,这已经是给定的[1..]现在可以编译了,但是它会永远循环。为什么会永远循环?因为你从无限列表中取出 i 和 j 。这意味着它将从 x=3、i=1、j=1 开始,然后尝试 j 从 1 到无穷大的所有值,然后再尝试 i 的下一个值(所以换句话说,它永远不会尝试 i 的下一个值)我)。
所以我们需要做的是给出
i
和j
上限。一个容易选择的上限是x
(如果i
或j
大于x
(并且都不小于比 1),i+j+2*i*j
不可能等于x
),所以你得到:这可行,但仍然可以简化一点一点:如果我们从列表中取出
j
[i..n]
而不是[1..n]
,我们保证j
至少为i
> 并且我们不再需要条件i<=j
,因此我们可以编写:PS:这样做(迭代所有 x,然后迭代
i 的所有可能值
和j
分别x
) 效率有点低,因此您可能会重新考虑您的方法。另一方面,如果您需要的只是有效的东西,那就没问题。First of all you have a nested list comprehension, so you're creating a list of lists, so the return type should be
[[Int]]
(list of lists of ints) and not[Int]
(list of ints).Second of all
xs
is a number (because you take it out of a list of numbers), but its name suggests that it's a list and when you dox <- xs
you're actually treating it as if it was a list.In response to your edit: I don't really see why you thought you needed nested list comprehensions for this. If we just remove the nesting from your code, we get something that is pretty close to working (I've also renamed
xs
tox
because calling a numberxs
is just confusing - I've also removed the condition thati
is at least 1 because that's already a given since you takei
from the list[1..]
):Now this compiles, but it will loop forever. Why does it loop forever? Because you take i and j from infinite lists. This means it will start with x=3, i=1, j=1 and then try all values for j from 1 to infinity before it will try the next value of i (so in other words it will never try the next value of i).
So what we need to do is to give
i
andj
upper bounds. An easy upper bound to pick isx
(ifi
orj
are greater thanx
(and neither is smaller than 1),i+j+2*i*j
can't possibly be equal tox
), so you get:This works, but it can still be simplified a bit by somewhat: If we take
j
from the list[i..n]
instead of[1..n]
, we guarantee thatj
is at leasti
and we don't need the conditioni<=j
anymore, so we can write:PS: Doing it this way (iterating over all x and then iterating over all possible values of
i
andj
for eachx
) is a bit inefficient, so you might reconsider your approach. On the other hand if all you need is something that works, this is fine.首先,函数名不能是大写。
xs <- [3..n]
表示xs
是Int
,但是x <- xs
> 将其用作列表。其余的理解看起来也有点奇怪。如果您愿意解释一下您到底想做什么,我们也许可以提供更多帮助。 :-)
[编辑]
通过使用
[i+j+2*i*j| 获得无限的数字列表。 j <-[2..], i<-[1..(j-1)]]
,但未排序。 <代码>[x| x <-[3..(2*n*n)],j <-[2..n],i<-[1..(j-1)],x==i+j+2 *i*j] 给出所有小于 2n² 的数字的排序列表。First, a function name must not be upper-case.
xs <- [3..n]
means thatxs
is anInt
, butx <- xs
uses it as a list.The rest of the comprehension looks a little bit strange, too. If you care to explain what exactly you want to do, we might be able to help a little bit more. :-)
[Edit]
You get an infinite list of your numbers by using
[i+j+2*i*j| j <-[2..], i<-[1..(j-1)]]
, but it's not sorted.[x| x <-[3..(2*n*n)], j <-[2..n], i<-[1..(j-1)], x==i+j+2*i*j]
gives a sorted list of all such numbers smaller than 2n².让我们从您拥有的开始吧。
这里的基本问题是您不需要嵌套列表理解。
这将编译。但正如您所怀疑的那样,这段代码还有更多错误。
我们先从条件说起。考虑到
i <- [1..]
,测试i>=1
是多余的。同样,如果我们从
i
而不是1
开始j
,我们就可以摆脱i<=j
条件。代码>.应该清楚的是,
j
的值大于(n - i) `div` (1 + 2 * i)
不可能导致x ≤ <代码>n。
同样,
i
的值n `div` 3
或以上不可能导致x
≤n
。至此,我们已经做了足够的事情来实际生成结果。但存在重复值(例如,当 (i,j) 为 (1,7) 或 (2,4) 时,您得到 x = 22),我认为您不希望这样做。
我们使用
Data.List
中的nub
过滤掉它们。当我们首先可以构造
x
来满足某个条件时,无需检查 x 是否满足该条件。 (您仍然希望满足自己 3 ≤ x ≤ n 的要求。)这样效率更高。结果不再按升序排列,因此让我们确保它们是按升序排列的。
在风格点上,加倍和加一是与确保 x 可以表示为 i+j+2*i*j 不同的计算,因此让我们将它们分开。
这使我们能够从列表理解中删除 x。
完毕。
Let's start with what you've got.
The basic problem here is that you don't need a nested list comprehension.
This will compile. But there is, as you suspect, a lot more wrong with this piece of code.
Let's start with the conditions. Testing for
i>=1
is superfluous, given thati <- [1..]
.Similarly, we can get rid of the
i<=j
condition if we startj
off ati
instead of at1
.It should be clear that values of
j
greater than(n - i) `div` (1 + 2 * i)
cannot possibly result in anx
≤n
.Similarly, values of
i
ofn `div` 3
or above cannot possibly result in anx
≤n
.At this point we have done enough for
something
to actually generate results. But there are duplicate values (e.g. when (i,j) is either (1,7) or (2,4) you get x = 22), which I assume you don't want.We filter them out using
nub
fromData.List
.There's no need to check that
x
satisfies a condition when we could constructx
to satisfy that condition in the first place. (You will want to satisfy yourself that 3 ≤ x ≤ n still.) This is more efficient.The results are no longer coming out in ascending order, so let's make sure they do.
On a style point, the doubling and adding one is a separate calculation from ensuring that x can be expressed as i+j+2*i*j, so let's split them up.
This allows us to get rid of x from the list comprehension.
Done.