2010-01-28 92 views
3

考虑以下几点:在Haskell中,有没有办法在构造函数上使用参数做“elem”?

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

有没有办法做下面的测试?

elem (A2 _) x == True 
+1

似乎我已经找到了替代解决方案:([z |(A2 z)< - x]/= []) – me2 2010-01-28 09:25:00

+6

如果你想nitpicky你最好使用'null'而不是'/ = []',因为它不需要Ord约束:not $ null [()| A2 _ < - x] – Martijn 2010-01-28 09:44:28

回答

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

elem (A2 undefined) x == True 

当然,这具有超出您要求的效果。

+0

在我的例子中,我认为([z |(A2 z)< - x]/= [])是最简单的,因为我只需要使用它一次,但我相信定义A的一个实例可能最恰当的选择。谢谢,ephemient。 – me2 2010-02-01 02:06:24

+1

@ me2:不要使用'/ = []';相反,使用'不。 null'。有关基本原理,请参阅http://www.haskell.org/haskellwiki/Haskell_programming_tips#Don.27t_ask_for_the_length_of_a_list_when_you_don.27t_need_it。 – ephemient 2010-02-01 03:26:04

8

不,但您可以使用任何改写。

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

否,原因有二:

  1. 对这种表达没有语法支持。

  2. elem需要一个具体的第一个参数来在作为第二个参数传入的列表中进行搜索(所以你不能通过对语法的一些小修改来完成)。

您可以使用Data.List.find代替:

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

更新:嗯,迪特里希打我,但我会离开这里了这个答案的替代解决方案(以及在上面的解释,FWIW )。

2

使用模板的Haskell A液:

{-# 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”中删除。

2

要扩大迪特里希的回答是:

如果你只是想匹配一个构造函数的名字,不顾一切领域,您可以使用此模式:A2 {}

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

此功能将继续,如果你以后决定另一个字段添加到A2构造工作。


而且,如果你正在使用ephemient Eq情况下,你也可以把它像这样:

elem (A2 {}) 

同样,无视所有字段(它们初始化为底部)。

1

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

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

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

即键入和编译器pipleine的一部分运行通过漂移产生的是*函数的模块中的所有的数据类型的源代码:

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

或者,也可以使用“派生”。使用上面的代码,删除{ - ! !... - }指令,并插入:

{-! 
deriving instance Is Foo 
!-} 

或者你可以节省一些打字和修改原来的代码如下:

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

和 “导出” 将产生:

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

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

derive住在Hackage上,而DrIFT可以在别处找到。

相关问题