2017-04-20 138 views
10

我不知道如何重新分配函數中的變量。如何在Haskell中的函數中重新分配變量?

例如,

elephant = 0 

function x = elephant = x 

爲什麼不這項工作?

+1

你要定義一個變量還是要重新 - 分配一個現有的變量?我在問,因爲你的例子看起來像你正試圖改變全局'elephant'變量的值。 – sepp2k

+0

即時嘗試重新分配一個現有的變量。 – Fl4mer

+37

在這兩種情況下,我認爲你正在擊中S.O.太快了,需要學習更多的語法和語言原語。我建議你通過閱讀來學習更多的Haskell。例如,[wikibooks](https://en.wikibooks.org/wiki/Haskell)和「函數式編程工藝」是開始的好地方。 –

回答

43

im trying to re-assign an existing variable

你不能在Haskell中做到這一點。你可以通過使用IORef來完成某些事情,但這很少是問題的正確解決方案 - 當然不是初學者可能遇到的情況。

相反,您應該重新設計您的程序邏輯,以便它不需要可變變量的功能。

+5

在這一點上,我懷疑有任何程序邏輯來重新設計。 OP只想知道如何處理Haskell中的其他語言。 –

106

Haskell是一個偉大的imperative語言,編寫可以重新分配狀態的程序是一個非常有趣的高級話題!這絕對不是你現在想要的方法,但有一天會回來

它需要一點努力去定義一個模擬全局可變變量的環境。然而,一旦你掌握了它,類型的精確性就變得非常方便了。

我們將使用lensmtl庫。

{-# LANGUAGE TemplateHaskell #-} 

import Control.Lens 
import Control.Monad.State 

大家都知道,大象是整數。

type Elephant = Integer 

你想要一個程序,其全局可變狀態有一頭大象。首先讓我們來定義一下大象的含義。 Lens很好地捕捉了這個概念。現在

class HasElephant a 
    where 
    elephant :: Lens' a Elephant 

,我們可以定義function,它分配一個新的價值elephant

function :: (MonadState s m, HasElephant s) => Elephant -> m() 
function x = 
    elephant .= x 

約束MonadState s mHasElephant s都在說我們的程序必須能夠持有某種類型s的可變狀態,類型s必須有大象。

我們還定義一個打印大象的程序。

printElephant :: (MonadState s m, HasElephant s, MonadIO m) => m() 
printElephant = 
    use elephant >>= (liftIO . print) 

這個程序執行I/O(印刷),所以我們有一個附加的約束MonadIO m,說我們的節目類型m必須能夠做I/O。

非洲森林大象(Loxodonta cyclotis)是一種在剛果盆地發現的森林棲息物種。

data Congo = Congo 
    { _congoElephant :: Elephant 
    } 
makeLenses ''Congo 

我們必須定義Congo有一頭大象的方式。

instance HasElephant Congo 
    where 
    elephant = congoElephant 

現在我們可以編寫一個示例程序。我們的程序將打印elephant的值,然後更改elephant的值,然後再次打印。

main' :: StateT Congo IO() 
main' = 
    do 
    printElephant 
    function 2 
    printElephant 

然後我們可以運行這個程序。

main :: IO() 
main = Congo 0 & runStateT main' & void 

輸出是:

0 
2 
+24

雖然這些都是很好的事情要知道和使用一般,我覺得這可能不是最合適的時候談論'StateT',monad變壓器,類型和鏡頭......如果有人不知道這方面的哈斯克爾(沒有像C這樣的語言的方式賦值)並且以前沒有遇到過這種差異,我懷疑他們還沒有這方面的背景,甚至可能會嚇跑他們(我*可能*是錯的當然,但我有一個非常強烈的懷疑......)。 –

+35

@DavidYoung我不指望我的答案會提供任何即時效用的提問者。其他人已經這樣做了。這個答案在這裏,因爲我一直相信,偶爾瞥見一些你還不能理解的東西是有價值的,從你腳下的路徑向上看,並注視着山上的雲彩形狀。 –

+1

這是一個公平點。 –

24

Haskell是在函數式編程世界和函數式編程的領導者通常被稱爲「編程不分配。」這幾乎是功能編程的整個不使用分配。一旦你使用它,你就不再以「功能」的方式來做它了。當然有時候,FP會盡量減少這些時間。

所以,要回答你的問題,「爲什麼不工作?」首先,語法不正確。 =並不意味着在Haskell中賦值。它將一個名稱綁定到一個表達式。你不能這樣做兩次(在相同的範圍內)。換句話說,「變量」是不可變的(就像在數學中一樣)。其次,突變是一種副作用行爲,Haskell將這些行爲視爲必須在IO世界中完成的不純行爲。

我可以告訴你如何實際上變異在Haskell中的引用,但我不認爲這就是你需要在這一點上。

10

到可變x綁定到值v最原始的方法是編寫的函數採取x作爲參數,並傳遞給v該功能。

這有時可以用來「模擬」可變變量的效果。

例如,勢在必行代碼

// sum 0..100 
i = s = 0; 
while (i <= 100) { 
    s = s+i; 
    i++; 
} 
return s; 

成爲

final_s = f 0 0 -- the initial values 
    where 
    f i s | i <=100 = f (i+1) (s+i) // increment i, augment s 
     | otherwise = s    // return s at the end 

上面的代碼是不漂亮FP碼,但至少它是足夠接近的命令性代碼,使其能夠當場連接。


最後題外話:

當一個第一通知這一點,它通常是引誘到落入Blub paradox。人們可以很容易想到:「什麼!Haskell需要所有的東西來模擬一個簡單的任務?如果在語言Blub分配是微不足道的,並且模擬Haskell需要這麼多努力,那麼顯然Blub比Haskell好得多!」。這將是一個完美的Blub悖論案例:當一個Blub程序員轉向另一種語言時,他們立即察覺到Blub不能直接翻譯的內容,並且沒有注意到新語言的所有其他功能並不存在泡殼。 他們的思想現在在「Blub」中思考,它需要付出很大的努力才能適應新的模型。

幾乎與此相反,學習 FP和命令式編程是有用的,因爲當僅用於其中的一種時,學習其他範式並非微不足道。如果他們之間的差距很小,那麼爲了解決同樣的問題而學習兩種接近的方法是不值得的。

2

一般來說這不起作用,因爲您通常會進行不可變的聲明,而不是指定一系列操作。你可以這樣做:

elephant = 3 
main = print elephant 

但你也可以這樣做:

main = print elephant 
elephant = 3 

由於代碼不指定執行順序,也沒有辦法解釋多項任務作爲不是錯誤以外的任何。

如果你想指定的一系列操作,使用符號:

main = do 
    let elephant = 0 
    print elephant 
    let elephant = 1 
    print elephant 
    let elephant = 2 
    print elephant 

的代碼做塊順序執行,這樣可以有效地重新分配變量的方式,您可以在大多數編程語言中。

請注意,這段代碼實際上只是爲大象創建了一個新的綁定。舊的價值依然存在:

main = do 
    let elephant = 1 
    print elephant 
    let printElephant = print elephant 
    let elephant = 2 
    print elephant 
    printElephant 

因爲printElephant功能我定義依然採用大象的舊值,這樣打印:

1 
2 
1 
+3

你確實可以做到這一點,但是強調'let elephant = 1'和'let elephant = 2'確實不**重新分配變量'elephant'很重要。相反,他們只是引入了一個_new_變量,該變量恰好也被稱爲'大象'。然後,「印象大象」選擇最近的一次出現(更確切地說,是_narrowest共享範圍內的那個),但在這個範圍之外,老大象始終保持相同的值。我建議這不應該在實際的Haskell代碼中完成(實際上'ghc-Wall'會警告它)。 – leftaroundabout

+0

@leftaroundabout你說得對,我加了一點來說明不同之處。 此外,我知道這不是建議,但問題違背了語言所代表的一切。用一些可以推薦的東西很難回答這個問題。 –