在Haskell中,有没有办法在带有参数的构造函数上做“elem”?

时间:2010-01-28 09:11:12

标签: haskell

请考虑以下事项:

data A = A1 | A2 Integer
x = [A1, A2 999]
elem A1 x == True

有没有办法进行以下测试?

elem (A2 _) x == True

6 个答案:

答案 0 :(得分:8)

不,但你可以用任何一种方式改写。

hasA2 :: [A] -> Bool
hasA2 = any $ \x -> case x of { A2 _ -> True ; _ -> False }

答案 1 :(得分:4)

不,有两个原因:

  1. 对此类表达式没有句法支持。

  2. elem需要一个具体的第一个参数来搜索作为第二个参数传入的列表(所以你不能单独修改一些语法)。

  3. 您可以改为使用Data.List.find

    import Data.List
    isA2 A1     = False
    isA2 (A2 _) = True
    find isA2 [A1, A2 999]
    -- => Just (A2 999)
    

    更新:嗯,迪特里希打败了我,但我会在这里留下这个答案来替代解决方案(加上FWIW的解释)。

答案 2 :(得分:2)

使用Template Haskell的解决方案:

{-# LANGUAGE TemplateHaskell #-}
import Data.ADT.Getters
import Data.Maybe

data A = A1 | A2 Integer
$(mkADTGetters ''A)

hasA2 = any (isJust . gA2)

注意:Data.ADT.Getters位于"peakachu" hackage包中,暂时。此功能将添加到"derive",然后从“peakachu”中删除。

答案 3 :(得分:2)

扩展迪特里希的答案:

如果您只想匹配构造函数名称,忽略所有字段,则可以使用此模式:A2 {}

hasA2 :: [A] -> Bool
hasA2 = any $ \x -> case x of { A2 {} -> True; _ -> False }

如果您稍后决定向A2构造函数添加另一个字段,此函数将继续有效。


而且,如果你使用了流行的Eq实例,你也可以这样称呼它:

elem (A2 {})

再次,忽略所有字段(将它们初始化为底部)。

答案 4 :(得分:1)

instance Eq A where
    A1   == A1   = True
    A2 _ == A2 _ = True
    _    == _    = False

elem (A2 undefined) x == True

当然,这会产生超出您要求的效果。

答案 5 :(得分:1)

是的,这是可行的!如果您不喜欢模板haskell(在另一个答案中使用),那么您可以使用“DrIFT”或“derive”工具。

{-! global : is !-}
data Foo = A1 | A2 Int deriving (Show, Eq, Ord)

hasA2 :: [Foo] -> Bool
hasA2 = any isA2

这是您键入的代码,并且作为编译器pipleine的一部分,您通过DrIFT运行源代码,它为模块中的所有数据类型生成is *函数:

{-* Generated by DrIFT : Look, but Don't Touch. *-}
isA1 (A1) = True
isA1 _ = False
isA2 (A2 _) = True
isA2 _ = False

或者您可以使用“derive”。使用上面的代码,删除{ - ! ......! - }指令和插入:

{-!
deriving instance Is Foo
!-}

或者您可以保存一些输入并修改原始代码:

data Foo = A1 | A2 Int deriving (Show, Eq, Ord {-! Is !-})

并且“derive”将生成:

isA1 :: Foo -> Bool
isA1 (A1{}) = True
isA1 _ = False

isA2 :: Foo -> Bool
isA2 (A2{}) = True
isA2 _ = False

derive生活在Hackage上,DrIFT可以在其他地方找到。