请考虑以下事项:
data A = A1 | A2 Integer
x = [A1, A2 999]
elem A1 x == True
有没有办法进行以下测试?
elem (A2 _) x == True
答案 0 :(得分:8)
不,但你可以用任何一种方式改写。
hasA2 :: [A] -> Bool
hasA2 = any $ \x -> case x of { A2 _ -> True ; _ -> False }
答案 1 :(得分:4)
不,有两个原因:
对此类表达式没有句法支持。
elem
需要一个具体的第一个参数来搜索作为第二个参数传入的列表(所以你不能单独修改一些语法)。
您可以改为使用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