2015-02-23 67 views
2

問題,我有以下ADT:與應用型風格秒差距

type Program = [Expr] 
data Expr = 
    Num Int 
    | Bool Bool 
    | Binding String Expr 
    deriving (Show) 

這裏有一個變量綁定表達式形式lhs is rhs的,解析器。

binding :: Parser Expr 
binding = do 
    lhs <- word 
    spaces 
    string "is" 
    spaces 
    rhs <- expr 
    return $ Binding lhs rhs 

它工作正常,但是當我嘗試將其轉換爲應用樣式時,它會給出錯誤的結果。

binding :: Parser Expr 
binding = Binding <$> word <* (spaces *> string "is" *> spaces) *> expr 

在parenthesised部分與>>更換*>也不能工作。這兩個實現有什麼區別?是否有組合兩個解析器並忽略兩者的結果?

試圖用Debug.trace進行調試也沒有效果......沒有打印任何內容。

binding :: Parser Expr 
binding = (\x y -> trace (show (x, y)) (Binding x y)) <$> word <* (spaces *> string "is" *> spaces) *> expr 

解析器的其餘部分,上下文:

word :: Parser String 
word = many1 letter 

expr :: Parser Expr 
expr = binding <|> atom 

program :: Parser Program 
program = do 
    spaces 
    result <- many (expr <* spaces) 
    return result 
+0

快速猜測,但是不應該在'binding'定義中的'word'之後使用'(<*>)'? I.e:'binding = Binding <$> word <*>(spaces *> string「is」*> spaces)*> expr' – danem 2015-02-23 04:44:41

+0

這是行不通的?也許你應該提供更多的代碼。 http://lpaste.net/121008 – danem 2015-02-23 05:10:50

+0

你很快就發現了。:) 謝謝您的幫助! – user1953221 2015-02-24 03:02:42

回答

10

你的問題是,<$><*>等都是左聯想。這意味着,訂單:

binding = Binding <$> word <* (spaces *> string "is" *> spaces) *> expr 

將被解釋爲

binding = (Binding <$> word <* (spaces *> string "is" *> spaces)) *> expr 

這意味着它將解析,然後忽略最後expr之前的一切。作爲@icktoofay說,你可以寫預期的版本:

binding = Binding <$> word <* spaces <* string "is" <* spaces <*> expr 

而無需任何括號可言,因爲左關聯的。

+0

感謝您的解釋! – user1953221 2015-02-24 03:02:14

6

@danem是正確的,請嘗試:

binding :: Parser Expr 
binding = Binding <$> word <*> (spaces *> string "is" *> spaces *> expr) 

完整的源:http://lpaste.net/121011

你的原始定義解析這樣:

binding = ((Binding <$> word) <* (spaces *> string "is" *> spaces)) *> expr 

即它具有something *> expr的形式,所以返回值完全由最後的expr確定。 lhs和is標記被解析但被丟棄。

這裏是如何的子表達式類型檢查:

Binding      :: String -> Expr -> Expr 
(Binding <$> word)   :: Parser (Expr -> Expr) 
(Binding <$> word) <* (...) :: Parser (Expr -> Expr) 

所以我們看到,由於鑽營和我們丟棄的something結果其實一切類型檢查。

+1

看起來很正確(雖然你可以使用Binding <$> word <* spaces <* string「爲」<* spaces <*> expr「)刪除括號,但是我想對試圖解決的問題以及爲什麼這個問題有解釋會使這個更有價值的答案。 – icktoofay 2015-02-23 05:30:10

+0

好主意 - 我重新修改了答案。 – ErikR 2015-02-23 06:35:12

+0

有趣的替代解決方案!讓我對這些操作員的工作方式有了新的認識。 – user1953221 2015-02-24 03:01:28