匹配数据而无需模式匹配

时间:2017-01-09 23:24:17

标签: haskell

如何在没有模式匹配的情况下检查变量是否属于某种数据类型?

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

2 个答案:

答案 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)isAisB模式匹配不需要额外的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并且没有任何参数的类型构造函数,它就可以工作。