2011-10-13 34 views
1

我想在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是整數而我< = j和i> = 1。對於這個子集列表,我想將函數2 * x + 1應用於每個元素x並輸出最終列表。
希望有道理。

回答

4

首先你有一個嵌套的列表理解,所以你創建一個列表的列表,所以返回類型應該是[[Int]](整數列表的列表)而不是[Int](整數列表)。

其次xs是一個數字(因爲你把它從數字列表中拿出來),但它的名字暗示它是一個列表,當你做x <- xs時,你實際上把它當作是一個列表。

迴應你的編輯:我真的不明白你爲什麼認爲你需要嵌套列表解析。如果我們只是從代碼中刪除嵌套,我們得到的東西非常接近工作(我也將xs更名爲x,因爲調用xs只是令人困惑 - 我也刪除了i至少爲1的條件因爲這是已經給定的,因爲你把i從列表[1..]):

[ 2 * x + 1 | x <- [3..n], i <- [1..],j <-[1..] ,x == i+j+2*i*j,i<=j] 

現在這個編譯,但它會永遠循環下去。爲什麼它會永遠循環?因爲你從無限列表中取出i和j。這意味着它將以x = 3,i = 1,j = 1開始,然後在它嘗試下一個i值之前嘗試j從1到無窮大的所有值(換句話說,它不會嘗試下一個值一世)。

所以我們需要做的是給ij上限。一個簡單的上限挑選是x(如果ijx更大(既不是小於1),i+j+2*i*j不可能等於x),讓您得到:

[ 2 * x + 1 | x <- [3..n], i <- [1..x],j <-[1..x], x == i+j+2*i*j, i<=j] 

該作品,但它仍然可以通過稍微簡化了一下:如果我們把j從列表[i..n]代替[1..n],我們保證j至少i,我們並不需要的條件i<=j了,所以我們可以這樣寫:

[ 2 * x + 1 | x <- [3..n], i <- [1..x], j <-[i..x], x == i+j+2*i*j] 

PS:這樣做(遍歷所有x,然後遍歷所有可能的值ij,每個x)效率有點低,所以您可能會重新考慮您的方法。另一方面,如果你所需要的只是有用的東西,那就沒問題。

+0

正如我所懷疑的,我正在以不止一種方式解決這個問題。我最終確實需要[Int]。所以我想我需要做一些超越理解的事情。我也看到xs是一個數字的問題。請參閱編輯。 – atlantis

1

首先,函數名不能是大寫。

xs <- [3..n]表示xsInt,但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]給出了一個小於2n2的所有這樣的數字的排序列表。

0

讓我們從你所擁有的開始。

something n = [[ 2 * x + 1 | x <- xs]|xs <- [3..n],i <- [1..],j <-[1..] ,xs == i+j+2*i*j,i<=j,i>=1] 

這裏的基本問題是,你不需要嵌套的列表理解。

something n = [ 2 * x + 1 | x <- [3..n], i <- [1..], j <- [1..], x == i+j+2*i*j, i<=j, i>=1] 

這會編譯。但是,正如你懷疑的那樣,這段代碼有更多的錯誤。

讓我們從條件開始。考慮到i <- [1..],測試i>=1是多餘的。

something n = [ 2 * x + 1 | x <- [3..n], i <- [1..], j <- [1..], x == i+j+2*i*j, i<=j] 

同樣,如果我們在i而不是在1開始j關閉,我們可以擺脫i<=j條件。

something n = [ 2 * x + 1 | x <- [3..n], i <- [1..], j <- [i..], x == i+j+2*i*j] 

應該清楚的是,超過(n - i) `div` (1 + 2 * i)更大的j值不可能導致xn

something n = [ 2 * x + 1 | x <- [3..n], i <- [1..], j <- [i .. (n - i) `div` (1 + 2 * i)], x == i+j+2*i*j] 

同樣,的n `div` 3i或上述的值不可能導致xn

something n = [ 2 * x + 1 | x <- [3..n], i <- [1 .. (n `div` 3) - 1], j <- [i .. (n - i) `div` (1 + 2 * i)], 
          x == i+j+2*i*j] 

在這一點上,我們已經做了足夠的something來實際生成結果。但是有重複的值(例如,當(i,j)是(1,7)或(2,4)時,你得到x = 22),我假設你不想要。

我們使用nubData.List中篩選出來。

something n = nub [ 2 * x + 1 | x <- [3..n], i <- [1 .. (n `div` 3) - 1], 
           j <- [i .. (n - i) `div` (1 + 2 * i)], x == i+j+2*i*j] 

有沒有必要檢查x滿足時,我們可以構建x滿足擺在首位的是條件的條件。 (你會想自己滿足3≤x≤n仍然)。這樣更有效率。

something n = nub [ 2 * x + 1 | i <- [1 .. (n `div` 3) - 1], j <- [1 .. (n - i) `div` (1 + 2 * i)], 
           let x = i+j+2*i*j] 

結果不再按照升序排列,所以讓我們確保他們這樣做。

something n = sort $ nub [ 2 * x + 1 | i <- [1 .. (n `div` 3) - 1], j <- [1 .. (n - i) `div` (1 + 2 * i)], 
             let x = i+j+2*i*j] 

在一個風格點,倍增和添加一個是從確保X單獨計算可以被表示爲I + J + 2 * I *∫,因此讓我們分裂起來。

something n = sort $ map f $ nub [ x | i <- [1 .. (n `div` 3) - 1], j <- [1 .. (n - i) `div` (1 + 2 * i)], 
            let x = i+j+2*i*j] 
    where f x = 2 * x + 1 

這使我們能夠從列表理解中擺脫x。

something n = sort $ map f $ nub [ i+j+2*i*j | i <- [1 .. (n `div` 3) - 1], 
               j <- [1 .. (n - i) `div` (1 + 2 * i)]] 
    where f x = 2 * x + 1 

完成。