2015-05-08 28 views
2

我試圖使用無可辯駁的模式和AS綁定到一個函數,評估反向波蘭符號表達式。Haskell AS綁定在無可辯駁的模式

這裏是我的代碼:

resolveRPN :: String -> [Integer] 
resolveRPN = foldl helper [] . words 
    where 
     helper [email protected](x1:x2:xs) el 
      | el == "+" = (x2 + x1) : xs 
      | el == "-" = (x2 - x1) : xs 
      | el == "*" = (x2 * x1) : xs 
      | el == "/" = (x2 `div` x1) : xs 
      | otherwise = (read el) : stack    

基本上無可辯駁的,如果你給一個列表少於2個元素,但這應該僅用於將失敗「+ - * /」。 如果該函數應用於「10 10」,它應該只使用「其他」並使用AS綁定「堆棧」,不應該試圖將其分解爲構造函數,但似乎它不起作用。

例如,如果我使用助手摺疊並使用[0,0]作爲累加器,即使不需要此值,即使正常工作也能正常工作。

有人可以解釋爲什麼這段代碼仍然提出「無可辯駁的模式」,除非?或Haskell如何評估這個?

下面是簡化代碼:

notWorking :: [Int] 
notWorking = helper [] "10" 
     where 
      helper [email protected](x1:x2:xs) el = (read el) : stack 

working:: [Int] 
working = helper [] "10" 
    where 
     helper ~stack el = (read el) : stack 
+0

你的架構不好,你應該感覺不好。解析與評估分離。 – rightfold

+3

@rightfold我對此有一個解決方法使用第二個用'(x1:x2:xs)= stack'的地方,但我沒有反思「我怎樣才能解決這個問題」,但「Haskell如何工作,爲什麼這不是工作「 –

回答

1

的經驗法則是:

  • 顛撲不破/懶人模式如果p變量x被徵求~p匹配一切
  • ,考慮所有構造函數中的p從除x到達的語法樹向下移動向下跨越~:匹配的值將被評估爲與這些構造函數匹配
  • 如果匹配abov Ë失敗,拋出一個異常

例子:

case value of ~(x,y:ys,~(z,w:ws)) -> ... 
  • 如果我們沒有什麼要求,然後value不會被評估
  • 如果我們要求xyys,然後value將根據需要進行評估以匹配y:ys(和三聯體)
  • 如果我們要求zwws,然後value將盡可能多的需要相匹配y:ysw:ws評估(和三和一對)

測試:

> case undefined of ~(x,y:ys,~(z,w:ws)) -> "hello" 
"hello" 
> case (3,undefined,(4,[1])) of ~(x,y:ys,~(z,w:ws)) -> x 
*** Exception: Prelude.undefined 
> case (3,[],(4,[1])) of ~(x,y:ys,~(z,w:ws)) -> x 
*** Exception: Irrefutable pattern failed for pattern (x, y : ys, ~(z, w : ws)) 
> case (3,[0],(4,undefined)) of ~(x,y:ys,~(z,w:ws)) -> x 
3 
> case (3,[0],(4,[])) of ~(x,y:ys,~(z,w:ws)) -> x 
3 
> case (3,[],(4,[1])) of ~(x,y:ys,~(z,w:ws)) -> z 
*** Exception: Irrefutable pattern failed for pattern (x, y : ys, ~(z, w : ws)) 
> case (3,[0],(4,[])) of ~(x,y:ys,~(z,w:ws)) -> z 
*** Exception: Irrefutable pattern failed for pattern (z, w : ws) 

在我看來,語義可能如果~下的每個子模式表現得好像它在上面有~那樣更好。例如。如果~(x,y:ys)等於~(x,~(y:ys))。不過,當前的語義確實允許更多的靈活性。


即使存在「as」模式,該規則也適用。例如,在

case value of [email protected] ~(x,y:ys,[email protected](z,[email protected](w:ws))) -> ... 

苛刻a不會評估value但苛刻的任何其他變量 會導致value被如此評價相匹配的三倍。 此外,要求任何x,y,ys也將導致評估匹配 y:ys中的列表構造函數。相反,匹配bz,c,w,ws中的任何一個將導致value進一步評估,以便匹配(z,[email protected](w:ws))以及列表w:ws(其在第二個~之下)。

--Here is an example with "as" pattern outside that will succeed 
> case (1,[],(2,[3])) of [email protected] ~(x,y:ys,[email protected](z,[email protected](w:ws))) -> a 
(1,[],(2,[3])) 

--This will fail because the triple as well as y:ys will be evaluated along a 
> case (1,[],(2,[3])) of [email protected](x,y:ys,[email protected](z,[email protected](w:ws))) -> a 
*** Exception: Irrefutable pattern failed for pattern [email protected](x, y : ys, [email protected](z, [email protected](w : ws))) 

在你的代碼,你可以簡單地把~這樣外「的」結合:

helper [email protected] ~(x1:x2:xs) el 
    | el == "+" = (x2 + x1) : xs 
    | el == "-" = (x2 - x1) : xs 
    | el == "*" = (x2 * x1) : xs 
    | el == "/" = (x2 `div` x1) : xs 
    | otherwise = (read el) : stack 

,將工作的優良任何有效的RPN輸入。

+0

我的問題不在於理解'thumb',而是與它結合使用作爲綁定,我認爲在這個表達式中,'〜stack @(x1:x2:xs)'拇指只適用於'(x1:x2:xs)'而不是'stack'。我開始懷疑,綁定只是'(x1:x2:xs)'的語法糖',這就是失敗的原因。 –

+0

你可以用'as as pattern'來適應你的答案,所以我可以接受你的答案嗎? –

+0

@GabrielCiubotaru我加了一個例子as模式 – chi

0

當我們嘗試打印生成的列表中無可辯駁的模式失敗:

head $ resolveRPN "2 4 +" -- 6, no error 
resolveRPN "2 4 +" -- error 

在上面的例子中,我們沒有一個適當的[]在結果列表的末尾。相反,我們有一個無可辯駁的(:)模式,它會引發錯誤。換句話說,即使我們沒有真正嘗試訪問模式中的頭部或尾部,~(x:xs)也不能用作空列表。

+0

當使用head $ resolveRPN」2 4 +「正在工作時,由於其他分支上的haskell懶惰:它只評估(讀取el)並且根本不關心堆棧,因爲打印結果不需要此值 –

+0

確實如此。答案中可能有些東西不清楚嗎? –

+0

如果你對這個函數應用「2 4+」:對於前2個元素應該只使用堆棧並且不應該嘗試將它分割成元素(因爲AS綁定),此時「+」將被評估爲已經有2個元素在acc:2和4中。問題在於,即使對於「2 2」也是因爲模式而失敗,但這不應該是因爲我只使用AT綁定,所以它不應該在意堆棧是否可以滑動或不是 –

3

無可辯駁的模式是申請[email protected](x1:x2:xs)不是每一個,所以當你試圖提取stack這將自動評估(x1:x2:xs)

這個問題只能進行模式匹配,但不作爲綁定定義hepler這樣用無可辯駁的是固定的:

helper [email protected] ~(x1:x2:xs) el 
     | el == "+" = (x2 + x1) : xs 
     | el == "-" = (x2 - x1) : xs 
     | el == "*" = (x2 * x1) : xs 
     | el == "/" = (x2 `div` x1) : xs 
     | otherwise = (read el) : stack 

,這將永遠不會失敗的有效表達。

+0

我在GHCi做了一個快速測試,我不得不使用另一對圓括號:'helper stack @(〜(x1:x2:xs))el ...'。 – chi

+0

@chi這是在.hs文件中工作 –

+0

你是對的:我正在使用'stack @〜(...'而沒有間隔空間 – chi