2017-03-01 87 views
1

我在Haskell,在那裏我有一條線,確實是這樣寫的一段代碼:如何修改,而不進入無限循環的Haskell列表?

addElement :: [a] -> a -> [a] 
addElement list elem = list ++ [elem] 

我需要(或者至少,我是這樣認爲的),這樣的功能對於增加的目的我正在實現的圖形數據結構的頂點列表中的新頂點。現在,我可以這樣稱呼這個功能

newlist = addElement oldlist elem 

和一切工作正常。但是,如果我寫

mylist = addElement mylist elem 

,然後嘗試做MYLIST任何呼叫終止後(它),我進入無限循環,如果我理解正確的話,這是由於哈斯克爾懶惰的評價或者類似的東西(mylist被擴大到addElement (addElement ... elem) elem,如果我得到了它吧?)。

這當然是壞我的特定實現,因爲我的目的,我現在每次我需要一個元素添加到列表中的時間,使新的​​列表。那麼,如何創建一個以我想要的方式工作的元素添加功能?

+0

mylist = addElement mylist elem'這不是一個賦值,它是一個等式。 Haskell沒有更新。在上下文中顯示您的嘗試。你如何建立mylist? –

+0

那麼,我基本上先運行mylist = []',然後說'mylist = addElement mylist 3'。第二個調用等同於'mylist = mylist ++ [3]'。如果我然後在ghci中鍵入'id mylist',例如沒有任何反應,我被困在循環中。所以我應該認爲在Haskell中不可能有一個'addElement'函數,最終會以'id mylist'導致'[3]'? –

+0

不,請顯示您正在嘗試構建mylist的整個函數。 –

回答

3

首先mylist = addElement mylist elem是一個等式,它是不是轉讓。這是計算一次:因爲Haskell是一個說明性語言,你不能改變一個變量:一旦你給它一個價值,它總是有一個值。因此

你的公式將導致:

mylist = addElement mylist elem 
     = addElement (addElement mylist elem) elem 
     = addElement (... (addElement mylist elem) ...) elem 

你的想法。

不過,你不需要每次構建一個完整的新名單:你可以簡單地使用(h:t)追加到頭部

addElement :: [a] -> a -> [a] 
addElement t h = (h:t) 

這將構建一個「新」名單O(1)一個可重用舊列表作爲尾。如前所述,元素將被添加到前面。

解決該問題的另一種方法是使用差異列表。下面的列表表示爲:

type DiffList a = a -> [a] 

和空列表是:

emptyDiffList :: DiffList a 
emptyDiffList = \x -> x 

在這種情況下,你地面與差異列表:

groundDiffList :: DiffList a -> [a] 
groundDiffList x = x [] 

,你可以添加到列表末尾的元素與:

addElement :: DiffList a -> a -> DiffList a 
addElement l el = \x -> l (el:x) 

不過你總是需要爲「新名單」創建一個新的變量:你不能一下子給mylist另一個值(你當然可以使用遞歸的,但在這種情況下,那些在技術上兩種不同變量:調用者mylist,以及調用者mylist)。

+0

謝謝你的回答,我認爲你的第一段和最後一段最能回答我的問題。因此,我必須爲每個「新列表」引入新變量的事實基本上是我必須在Haskell中生活的一個侷限性,並且我(或任何其他人)都無法做到這一點。這足以讓我接受。 –

+4

@ A.Sh一個人的侷限是另一個人的解放。 –

+2

@ A.Sh:的確,雖然它不是一個真正的限制:你可以在不重新定義變量的情況下編寫任何程序。此外,我個人認爲這樣做有一定的侷限性,因爲您不必通過流程推理變量值的變化。在我看來,聲明性語言往往更容易調試。 –