如何在没有模式匹配的情况下检查变量是否属于某种数据类型?
data MyData = A | B | C char
deriving (Eq)
-- This works.
isA :: MyData -> Bool
isA x = x == A
-- This generates a compile error.
isC :: MyData -> Bool
isC x = x == C
修改:忘记添加deriving Eq
。
答案 0 :(得分:6)
作为术语,您要检查变量是否与某个数据构造函数匹配,而不是类型。您的所有值都是MyData
类型;你正在检查他们匹配的构造函数。
话虽如此,没有充分理由避免模式匹配。事实上,Haskell实现isA
的正确惯用方法是:
isA A = True
isA _ = False
或者,如果您愿意:
isA x = case x of { A -> True; _ -> False }
同样,实施isC
的正确方法是:
isC (C _) = True
isC _ = False
或:
isC x = case x of { C _ -> True; _ -> False }
如果你试图避免模式匹配,因为你担心它在某种程度上比测试平等效率低,所以不要理会这个概念。这是确定值的构造函数的最有效方法。
如果你试图避免模式匹配,因为你不喜欢语法或者对这种技术有某种个人的厌恶,那么你有我的同情心:学习Haskell对你来说将是一段悲惨的经历。
答案 1 :(得分:2)
据我所知,即使您的第一个示例在没有错误的情况下也无法编译
> ghci
...
Prelude> data MyData = A | B | C Char
Prelude> isA x = x == A
<interactive>:2:9: error:
• No instance for (Eq MyData) arising from a use of ‘==’
• In the expression: x == A
In an equation for ‘isA’: isA x = x == A
可以通过
轻松修复Prelude> data MyData = A | B | C Char deriving (Eq)
@Alexis King的建议评论定义
isC x = x == C{}
将编译但会引发运行时错误
isC (C 'a')
*** Exception: <interactive>:6:14-17: Missing field in record construction
如果我正确查看这是(a -> b)
没有Eq
实例的特例,因为一般情况下你不能(合理地)定义==
对[Double] -> Int
之类的内容说 - 唯一合理的定义相同的输入数据产生相同的输出数据 - 是不可行的。
如果您接受模式匹配 - deriving (Eq)
,isA
和isB
模式匹配不需要额外的isC
,则不需要此。
我找到了另一种奇怪的方式 - 但我们还需要改变类型并使用语言语用:
Prelude> :set -XDeriveFunctor
Prelude> data MyData a = A | B | C a deriving (Eq, Functor)
Prelude> isC x = fmap (const True) x == C True
Prelude> isC x = fmap (const ()) x == C ()
我认为你的问题有点像 - 我可以骑自行车没有腿 - 答案很明显,你需要一辆特殊的自行车。或者在你的情况下 - 如果你有deriving Eq
并且没有任何参数的类型构造函数,它就可以工作。