2013-04-11 126 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