Searching for ADT patterns with elem and find

Hi All, If I have an ADT, say data T = A String Integer | B Double | C deriving(Eq) and I want to find if a list (ts) of type T contains an element of subtype "B Double", must my "containsTypeX" function use a second "isTypeX" function as follows: isTypeB :: T -> Bool isTypeB (B _) = True isTypeB _ = False containsTypeB :: [T] -> Bool containsTypeB ts = maybe False (\x -> True) (find isTypeB ts) I understand that while something like "find C ts" will work, "find (isTypeB _) ts" will not, but is there no such thing as a pattern combinator(?), or lambda that could help with this situation. I find I have many individual "isTypeB" functions now. Regards, Paul

Hi Paul, maybe False (\x -> True) (find isTypeB ts) This can be more neatly expressed as: isJust (find isTypeB ts) But your entire thing can be expressed as: containsTypeB ts = any isTypeB ts I recommend reading through the Prelude interface and the List interface, it has many useful functions that will help. Thanks Neil ________________________________ From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Paul Keir Sent: 12 November 2008 10:09 am To: haskell-cafe@haskell.org Subject: [Haskell-cafe] Searching for ADT patterns with elem and find Hi All, If I have an ADT, say data T = A String Integer | B Double | C deriving(Eq) and I want to find if a list (ts) of type T contains an element of subtype "B Double", must my "containsTypeX" function use a second "isTypeX" function as follows: isTypeB :: T -> Bool isTypeB (B _) = True isTypeB _ = False containsTypeB :: [T] -> Bool containsTypeB ts = maybe False (\x -> True) (find isTypeB ts) I understand that while something like "find C ts" will work, "find (isTypeB _) ts" will not, but is there no such thing as a pattern combinator(?), or lambda that could help with this situation. I find I have many individual "isTypeB" functions now. Regards, Paul ============================================================================== Please access the attached hyperlink for an important electronic communications disclaimer: http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html ==============================================================================

Thanks Neil, Great. I hadn't noticed "isJust", and I'd forgotten "any". Actually I was browsing Prelude just the other day and picked up "zipWith f as bs" as a replacement for "map f $ zip as bs". Cheers, Paul -----Original Message----- From: Mitchell, Neil [mailto:neil.mitchell.2@credit-suisse.com] Sent: Wed 12/11/2008 10:23 To: Paul Keir; haskell-cafe@haskell.org Subject: RE: [Haskell-cafe] Searching for ADT patterns with elem and find Hi Paul, maybe False (\x -> True) (find isTypeB ts) This can be more neatly expressed as: isJust (find isTypeB ts) But your entire thing can be expressed as: containsTypeB ts = any isTypeB ts I recommend reading through the Prelude interface and the List interface, it has many useful functions that will help. Thanks Neil ________________________________ From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Paul Keir Sent: 12 November 2008 10:09 am To: haskell-cafe@haskell.org Subject: [Haskell-cafe] Searching for ADT patterns with elem and find Hi All, If I have an ADT, say data T = A String Integer | B Double | C deriving(Eq) and I want to find if a list (ts) of type T contains an element of subtype "B Double", must my "containsTypeX" function use a second "isTypeX" function as follows: isTypeB :: T -> Bool isTypeB (B _) = True isTypeB _ = False containsTypeB :: [T] -> Bool containsTypeB ts = maybe False (\x -> True) (find isTypeB ts) I understand that while something like "find C ts" will work, "find (isTypeB _) ts" will not, but is there no such thing as a pattern combinator(?), or lambda that could help with this situation. I find I have many individual "isTypeB" functions now. Regards, Paul ============================================================================== Please access the attached hyperlink for an important electronic communications disclaimer: http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html ==============================================================================

somebody pointed out a few months back that list comprehensions do this nicely:
containsTypeB ts = not $ null [x | (B x) <- ts]
no need for defining isTypeB.
not quite sure how you would write findBs :: [T]->[T] succinctly; maybe
findBs ts = [b | b@(B _) <- ts]
or
findBs ts = [B x | (B x) <- ts]
both of them compile but the first is ugly and the second is
inefficient (Tags a new T for every hit).
Tom
2008/11/12 Paul Keir
Hi All,
If I have an ADT, say
data T = A String Integer | B Double | C deriving(Eq)
and I want to find if a list (ts) of type T contains an element of subtype "B Double", must my "containsTypeX" function use a second "isTypeX" function as follows:
isTypeB :: T -> Bool isTypeB (B _) = True isTypeB _ = False
containsTypeB :: [T] -> Bool containsTypeB ts = maybe False (\x -> True) (find isTypeB ts)
I understand that while something like "find C ts" will work, "find (isTypeB _) ts" will not, but is there no such thing as a pattern combinator(?), or lambda that could help with this situation. I find I have many individual "isTypeB" functions now.
Regards, Paul
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Thanks Tom,
That is indeed a very elegant solution; I too often forget about the wonders of list comprehension.
I guess one drawback compared to Neil's suggested use of "any" (and staying with a separate "isTypeB") is that your solution will iterate over the entire list, regardless of an early hit.
But I don't think your second (as-pattern) solution for findBs is ugly; I quite like it actually.
Cheers,
Paul
-----Original Message-----
From: Tom Nielsen [mailto:tanielsen@gmail.com]
Sent: Wed 12/11/2008 12:39
To: Paul Keir
Cc: haskell-cafe@haskell.org
Subject: Re: [Haskell-cafe] Searching for ADT patterns with elem and find
somebody pointed out a few months back that list comprehensions do this nicely:
containsTypeB ts = not $ null [x | (B x) <- ts]
no need for defining isTypeB.
not quite sure how you would write findBs :: [T]->[T] succinctly; maybe
findBs ts = [b | b@(B _) <- ts]
or
findBs ts = [B x | (B x) <- ts]
both of them compile but the first is ugly and the second is
inefficient (Tags a new T for every hit).
Tom
2008/11/12 Paul Keir
Hi All,
If I have an ADT, say
data T = A String Integer | B Double | C deriving(Eq)
and I want to find if a list (ts) of type T contains an element of subtype "B Double", must my "containsTypeX" function use a second "isTypeX" function as follows:
isTypeB :: T -> Bool isTypeB (B _) = True isTypeB _ = False
containsTypeB :: [T] -> Bool containsTypeB ts = maybe False (\x -> True) (find isTypeB ts)
I understand that while something like "find C ts" will work, "find (isTypeB _) ts" will not, but is there no such thing as a pattern combinator(?), or lambda that could help with this situation. I find I have many individual "isTypeB" functions now.
Regards, Paul
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I guess one drawback compared to Neil's suggested use of "any" (and staying with a separate "isTypeB") is that your solution will iterate over the entire list, regardless of an early hit.
Nope, it will stop on the first one - Haskell is lazy like that :-)
Thanks, Neil
________________________________
From: haskell-cafe-bounces@haskell.org
[mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Paul Keir
Sent: 12 November 2008 1:45 pm
To: Tom Nielsen
Cc: haskell-cafe@haskell.org
Subject: RE: [Haskell-cafe] Searching for ADT patterns with elem
and find
Thanks Tom,
That is indeed a very elegant solution; I too often forget about
the wonders of list comprehension.
I guess one drawback compared to Neil's suggested use of "any"
(and staying with a separate "isTypeB") is that your solution will
iterate over the entire list, regardless of an early hit.
But I don't think your second (as-pattern) solution for findBs
is ugly; I quite like it actually.
Cheers,
Paul
-----Original Message-----
From: Tom Nielsen [mailto:tanielsen@gmail.com]
Sent: Wed 12/11/2008 12:39
To: Paul Keir
Cc: haskell-cafe@haskell.org
Subject: Re: [Haskell-cafe] Searching for ADT patterns with elem
and find
somebody pointed out a few months back that list comprehensions
do this nicely:
containsTypeB ts = not $ null [x | (B x) <- ts]
no need for defining isTypeB.
not quite sure how you would write findBs :: [T]->[T]
succinctly; maybe
findBs ts = [b | b@(B _) <- ts]
or
findBs ts = [B x | (B x) <- ts]
both of them compile but the first is ugly and the second is
inefficient (Tags a new T for every hit).
Tom
2008/11/12 Paul Keir

containsTypeB ts = not $ null [x | (B x) <- ts]
No need for the brackets on the left of the <-: not $ null [x | B x <- ts]
findBs ts = [b | b@(B _) <- ts]
or
findBs ts = [B x | (B x) <- ts]
both of them compile but the first is ugly and the second is inefficient (Tags a new T for every hit).
If optimised does it really create a new B tag for each node? That seems like something that could be optimised away by the compiler. Either way, the difference is probably minimal. (There may be possible space leaks if the compiler did share the B, but I can't think of any off hand) Thanks Neil
2008/11/12 Paul Keir
: Hi All,
If I have an ADT, say
data T = A String Integer | B Double | C deriving(Eq)
and I want to find if a list (ts) of type T contains an element of subtype "B Double", must my "containsTypeX" function use a second "isTypeX" function as follows:
isTypeB :: T -> Bool isTypeB (B _) = True isTypeB _ = False
containsTypeB :: [T] -> Bool containsTypeB ts = maybe False (\x -> True) (find isTypeB ts)
I understand that while something like "find C ts" will work, "find (isTypeB _) ts" will not, but is there no such thing as a pattern combinator(?), or lambda that could help with this situation. I find I have many individual "isTypeB" functions now.
Regards, Paul
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
============================================================================== Please access the attached hyperlink for an important electronic communications disclaimer: http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html ==============================================================================

On Wed, 2008-11-12 at 10:09 +0000, Paul Keir wrote:
Hi All,
If I have an ADT, say
data T = A String Integer | B Double | C deriving(Eq)
and I want to find if a list (ts) of type T contains an element of subtype "B Double", must my "containsTypeX" function use a second "isTypeX" function as follows:
isTypeB :: T -> Bool isTypeB (B _) = True isTypeB _ = False
containsTypeB :: [T] -> Bool containsTypeB ts = maybe False (\x -> True) (find isTypeB ts)
I understand that while something like "find C ts" will work, "find (isTypeB _) ts" will not, but is there no such thing as a pattern combinator(?), or lambda that could help with this situation. I find I have many individual "isTypeB" functions now.
In addition to what others have said, I recommend using functions like isTypeB :: T -> Maybe Double isTypeB (B d) = Just d isTypeB _ = Nothing You can recover the Bool version of isTypeB just by post-composing with isJust, but this version avoids needing partial functions and often is more what you want (i.e. it's a first-class "pattern"). Combining it with catMaybes is also a common pattern.

On Wed, Nov 12, 2008 at 10:20 AM, Derek Elkins
In addition to what others have said, I recommend using functions like isTypeB :: T -> Maybe Double isTypeB (B d) = Just d isTypeB _ = Nothing
You can recover the Bool version of isTypeB just by post-composing with isJust, but this version avoids needing partial functions and often is more what you want (i.e. it's a first-class "pattern"). Combining it with catMaybes is also a common pattern.
Although if you are using Maybe as a monad, these two pieces of code are equivalent: test1 t1 t2 = do d1 <- isTypeB t1 d2 <- isTypeB t2 return (d1 + d2) test2 t1 t2 = do B d1 <- return t1 B d2 <- return t2 return (d1 + d2) This is because pattern-matching in do-notation implicitly calls "fail" when the pattern match fails. -- ryan

Paul Keir wrote:
Hi All,
If I have an ADT, say
data T = A String Integer | B Double | C deriving(Eq)
and I want to find if a list (ts) of type T contains an element of subtype "B Double", must my "containsTypeX" function use a second "isTypeX" function as follows:
isTypeB :: T -> Bool isTypeB (B _) = True isTypeB _ = False
containsTypeB :: [T] -> Bool containsTypeB ts = maybe False (\x -> True) (find isTypeB ts)
Many other good posts have obviated the original question, but just to answer it directly. You can turn isTypeB into a lambda by using a case expression: isTypeB = \t -> case t of B _ -> True ; _ -> False And from there you can just inline the definition in order to remove isTypeB. Pattern matching in function definitions is just sugar for the case expression version, so this transformation is just what the compiler would be doing anyways. -- Live well, ~wren
participants (6)
-
Derek Elkins
-
Mitchell, Neil
-
Paul Keir
-
Ryan Ingram
-
Tom Nielsen
-
wren ng thornton