2013-12-08 79 views
0

我想教自己Haskell(來自OOP語言)。難以掌握不可變變量的東西。我正在嘗試排列主行中的2d數組。2d數組排序在Haskell

在java中,例如(僞):

int array[3][3] = **initialize array here 

for(i = 0; i<3; i++) 
    for(j = 0; j<3; j++) 
     if(array[i][j] < current_low) 
     current_low = array[i][j] 

我如何能實現在Haskell這個同樣的事情?如果我創建一個臨時數組以便在每次迭代之後添加低值,我將無法添加它,因爲它是不可變的,正確的?另外,Haskell沒有循環,對吧?

這是我知道在Haskell一些有用的東西:

main = do 
let a = [[10,4],[6,10],[5,2]] --assign random numbers 
print (a !! 0 !! 1) --will print a[0][1] in java notation 
--How can we loop through the values? 
+1

* Wince *。只是想明確指出從'[]'文字出來的數據結構是一個鏈表,而不是連續的內存塊。它不適合數字工作,但適合於教你自己Haskell如何替換循環。我很想知道聰明的FP人在回答這個問題時想出了什麼,但高效的數組排序是FP風格並不令人印象深刻的任務之一。 (好吧,我們拭目以待吧) – masonk

+0

@masonk:高效的數組排序是你從來不想自己做的任務之一**,除了教育目的。所以在這個任務中令人印象深刻的風格是一種風格,它允許您以通用的方式重用庫函數,而不需要太多的樣板。功能性編程非常擅長的一個方面! - 也就是說,確定有些應用程序需要使用陣列進行高效工作。事實上,在功能風格上做得不好。在Haskell中,你通常會側身進入一個'ST'ate monad(本地),在那裏使用一個命令式的算法。 – leftaroundabout

+0

底線是,在許多其他時候,Haskell的正確答案是抽出一個'ST'並開始以指令性風格開始混洗指針或原生值類型。我認爲這對於FP運動在這一點上很吝嗇是不利的。當你向他們展示一種在教語言時無用的假快速排序[1]時,感覺就像是誘餌和切換。當你通過K&R並閱讀他們的快速排序時,你正在閱讀在現實世界中有用的代碼。請在「教育學中的誠信」。 [1] http://augustss.blogspot.com/2007/08/quicksort-in-haskell-quicksort-is.html – masonk

回答

1

好了,好了,我要一刀。扎克,這個答案是爲了讓你思考遞歸和摺疊。遞歸,摺疊和貼圖是循環在功能樣式中被替換的基本方式。試着相信在現實中,嵌套循環的問題很少在函數式編程中自然出現。當你真的需要這樣做的時候,你經常會輸入一段特殊的代碼,叫做monad,你可以用命令式的方式做破壞性的寫操作。 Here's an example。但是,既然你在突破循環思考方面尋求幫助,我將專注於答案的這一部分。 @ leftaroundabout的答案也很好,你在這裏填寫他的定義minimum

flatten :: [[a]] -> [a] 
flatten [] = [] 
flatten xs = foldr (++) [] xs 

squarize :: Int -> [a] -> [[a]] 
squarize _ [] = [] 
squarize len xs = (take len xs) : (squarize len $ drop len xs) 

crappySort :: Ord a => [a] -> [a] 
crappySort [] = [] 
crappySort xs = 
    let smallest = minimum xs 
     rest = filter (smallest /=) xs 
     count = (length xs) - (length rest) 
    in 
     replicate count smallest ++ crappySort rest 

sortByThrees xs = squarize 3 $ crappySort $ flatten xs 
2

首先,Java代碼不那種東西。它只是找到最小的元素。而且,好吧,有一種明顯的Haskell解決方案......猜猜看,該函數被稱爲minimum!讓我們看看會發生什麼:

GHCI>:T最低
最低::奧德A => [A] - >一個

確定,所以它需要的值的列表,可以是比較(因此Ord)並輸出單個值,即最小值。我們如何將它應用於「2D列表」(嵌套列表)?那麼,基本上我們需要子列表的所有最小值中的最小值。所以我們先用極小

allMinima = map minimum a 

名單替換名單列表...然後使用minimum allMinima

緊湊採寫:

main :: IO() 
main = do 
    let a = [[10,4],[6,10],[5,2]] -- don't forget the indentation 
    print (minimum $ map minimum a) 

這一切!


事實上,「通過值循環」是一個非常不起作用的概念。我們一般不想談論單個的步驟需要採取的,而是想想我們想要的結果的屬性,並讓編譯器找出如何去做。在什麼情況下是正確的

  • 如果我們有一個清單,並期待在一個單一的價值... ...:因此,如果我們不允許使用預先定義minimum,這裏是如何考慮一下結果?那麼,如果它小於其他所有值。其他最小值是多少?確切地說,其中最小的。

    minimum' :: Ord a => [a] -> a 
    minimum' (x:xs) 
        | x < minimum' xs = x 
    
  • 如果不是更小,那麼我們就用最小其它數值的

    minimum' (x:xs) 
        | x < minxs = x 
        | otherwise = minxs 
    where minxs = minimum' xs 
    
  • 一兩件事:如果我們通過列表這樣遞歸,也將在某個時候沒有第一個元素留下來與某些東西比較。爲了防止這種情況,我們首先需要一個單一的元素列表的特殊情況:

    minimum' :: Ord a => [a] -> a 
    minimum' [x] = x  -- obviously smallest, since there's no other element. 
    minimum' (x:xs) 
        | x < minxs = x 
        | otherwise = minxs 
    where minxs = minimum' xs 
    
+0

是的,我知道java代碼沒有做任何事情。我只是想解決問題。我明白你的例子在做什麼。只需抓住所有列表的最小值。這絕對有幫助,但不是我所期待的。我怎樣才能建立這些最低限度的清單?爲了特別。 –

+0

所以你基本上想'allMinima',但排序?如何導入Data.List'排序$ map最小a'? – leftaroundabout

+0

如果沒有,那麼也許你應該正確地寫出你想要的命令式的東西。 – leftaroundabout