2011-02-06 38 views
11

[這個問題是由第9章中的「真實世界哈斯克爾」動機]

這裏有一個簡單的函數(砍倒要領):

saferOpenFile path = handle (\_ -> return Nothing) $ do 
     h <- openFile path ReadMode 
     return (Just h) 

爲什麼我需要一個$

如果處理的第二個參數是不是DO塊,我並不需要它。下面的作品就好了:

handle (\_ -> putStrLn "Error calculating result") (print x) 

當我試圖消除$編譯失敗。我可以得到它,如果我明確地加括號的工作,即

saferOpenFile path = handle (\_ -> return Nothing) (do 
     h <- openFile path ReadMode 
     return (Just h)) 

我能理解,但我想我很期待,當哈斯克爾擊中do應該想到「我開始塊」,而且我們不應該明確地把$打破。

我也想過推DO塊到下一行,像這樣:

saferOpenFile path = handle (\_ -> return Nothing) 
    do 
    h <- openFile path ReadMode 
    return (Just h) 

但是,這並不沒有括號工作,要麼。這讓我困惑,因爲以下工作:

add a b = a + b 

addSeven b = add 7 
    b 

我敢肯定,我只是達到,我接受它作爲「這只是你如何寫成語哈斯克爾」的地步,但沒有任何人有任何的角度給?提前致謝。

+0

對不起,夥計們,我不知道stackoverflow非常好。代碼只是垃圾。 (爲什麼沒有「預覽問題」)。我會嘗試重新發布它。 – Jonathan 2011-02-06 03:50:46

+0

只需點擊編輯器工具欄上的「代碼」按鈕(它看起來像一對大括號)。此外,預覽正好在您輸入的地方,實時更新... – Jon 2011-02-06 03:52:22

+1

啊,NoScript需要允許一個域!它現在看起來很好。謝謝,喬恩! – Jonathan 2011-02-06 03:54:20

回答

6

按照Haskell 2010 reportdo desugars這樣的:

do {e;stmts} = e >>= do {stmts}

do {p <- e; stmts} = let ok p = do {stmts} 
         ok _ = fail "..." 
        in e >>= ok 

對於第二種情況,這是相同的寫呢脫糖這樣的(和更容易說明的目的):

do {p <- e; stmts} = e >>= (\p -> do stmts)

因此,假設您這樣寫:

-- to make these examples shorter 
saferOpenFile = f 
o = openFile 

f p = handle (\_ -> return Nothing) do 
    h <- o p ReadMode 
    return (Just h) 

它desugars這樣:

f p = handle (\_ -> return Nothing) (o p ReadMode) >>= (\h -> return (Just h)) 

這是與此相同:

f p = (handle (\_ -> return Nothing) (o p ReadMode)) >>= (\h -> return (Just h)) 

即使你可能打算爲它的意思這個:

handle (\_ -> return Nothing) ((o p ReadMode) >>= (\h -> return (Just h))) 

tl; dr - 什麼時候語法被刪除,它不會像你認爲它應該括起整個語句(截至Haskell 2010)。

這答案只有AFAIK和

  1. 可能不正確
  2. 可能是過時的一天,如果它是正確的

注意:如果你對我說「,但實際的脫糖用途一個'let'語句應該組e >>= ok,對不對?「,那麼我會回答與tl; dr相同的do語句:它不會像您認爲的那樣使用小括號/ group。

10

這是由於操作Haskell的順序。函數應用綁定最緊密,這可能是混淆的來源。例如:

add a b = a + b 
x = add 1 add 2 3 

Haskell將此解釋爲:函數add應用於1,函數add。這可能不是程序員的意圖。 Haskell會抱怨期待Num的第二個參數,但是取而代之的是函數。

有兩個解決方案:

1)的表達可以被括號:

x = add 1 (add 2 3) 

哪個Haskell中會解釋:該函數添加應用到1,則值加2 3.

但是,如果嵌套變得太深,這可能會令人困惑,因此第二個解決方案。

2)$操作:

x = add 1 $ add 2 3 

$是適用的功能,它的參數操作。 Haskell將此讀爲:函數(add 1)應用於add 2的值3.請記住,在Haskell中,函數可以部分應用,因此(add 1)是一個參數的完全有效函數。

$操作符可以多次使用:

x = add 1 $ add 2 $ add 3 4 

你選擇哪種方案將被確定的,你認爲是在特定環境下更具可讀性。

10

這實際上不是特定於do -notation。你也不能寫如print if x then "Yes" else "No"print let x = 1+1 in x*x

您可以從語法定義在chapter 3 of the Haskell Report開始驗證這一點:一個do表達式或條件或let表達是lexp,但是功能應用的參數爲AEXPlexp通常無效,作爲aexp

當然,這並不能告訴你爲什麼選擇是在報告中做出的。如果我不得不猜測,我可能會推測它是擴展有用的規則「功能應用程序綁定比其他任何東西」更緊密,例如,do和它的塊之間的綁定。但我不知道這是否是最初的動機。 (我發現像print if x then ...這樣的被拒絕的表單很難閱讀,但那可能只是因爲我習慣閱讀Haskell接受的代碼。)

相關問題