2013-04-11 95 views
1

下面的Haskell代碼抱怨在最後第二行,當我試圖檢查表達式是否評估爲Cons _ _形式。 Haskell的錯誤信息是:「表達式上下文中的模式語法:_」 - 我想知道的是 - 有沒有辦法完成我想要做的事?看起來我試圖做的是在運行時檢查一個表達式的類型,從我讀過的內容可能意味着我可以更好地編程這個表達式?但是,因爲我是初學者,所以我不知道我是否在做這件事,特別是因爲我一直試圖在最後一個小時內做到這一點。Haskell類型檢查/模式匹配

data Val = Num Int | Nil | Cons Val Val 
    deriving (Eq, Show, Read) 

interpret_expr :: Prog -> Vars -> Expr -> Val 
interpret_expr _ _ (Isnum NilE) = Num 0 
interpret_expr _ _ (Isnum (ConsE _ _)) = Num 0 
interpret_expr _ _ (Isnum (NumE _)) = Num 1 
interpret_expr prog vars (Isnum expr) 
    | interpret_expr prog vars expr == Nil = Num 0 
    | interpret_expr prog vars expr == Cons _ _ = Num 0 
    | otherwise = Num 1 

回答

8
interpret_expr prog vars (Isnum expr) 
    | interpret_expr prog vars expr == Nil = Num 0 
    | interpret_expr prog vars expr == Cons _ _ = Num 0 
    | otherwise = Num 1 

你衛士的使用是無效的。你不能將一個函數(這裏是(==)函數)應用到一個模式。也就是說,你不能比較(使用Eq typeclass)和Cons _ _。你需要模式匹配一​​遍,它可以使用case .. of做到:

interpret_expr prog vars (Isnum expr) = case interpret_expr prog vars expr of 
    Nil -> Num 0 
    Cons _ _ -> Num 0 
    _ -> Num 1 
5

檢查值是否是特定的構造函數是常見的事情。很多時候,你會看到一個手寫的片段形式:

isCons (Cons _ _) = True 
isCons _   = False 

,它會被用作:

| isCons (interpret_expr prog vars expr) = Num 0 

這是很常見的各種源對源重寫工具將增加is[Some Constructor]功能(如:deriveDriFT)。我偏愛模板haskell解決方案(因爲它們不需要運行外部工具,並不是因爲TH非常乾淨或穩定)。如果你安裝了derive庫,然後你的代碼可能是這樣的:

import Data.Derive.Is 
import Data.DeriveTH 
import Language.Haskell.TH 

data Val = ... 
    deriving (Eq, Ord, Show) 

$(derive makeIs ''Val) 
+0

雖然這個答案是偉大的,我選擇另外一個,因爲它更簡單,就是做我想做的最簡單方法。不過,我很高興你告訴我,因爲我100%肯定我最終會需要這個,最初我以爲我會被告知不能,你不能檢查你是愚蠢的新手建設者,有時間重寫整個東西(數百行)!!! – nebffa 2013-04-11 09:03:50

+0

弗拉基米爾的答案絕對是正確的解決方案。我非常狹隘地將注意力集中在你呼出的線上,很高興你覺得它很有趣。 – 2013-04-11 16:23:44