
On 11/10/2014 03:28 AM, Mateusz Kowalczyk wrote:
On 11/10/2014 02:58 AM, Donn Cave wrote:
I'm guessing this isn't supported, but might be worth asking - can I extend a list comprehension like ['A' | A <- s] to multiple values? Like,
data V = A | B | C
pv :: [V] -> [Char] pv [] = [] pv (A:x) = 'A':(pv x) pv (B:x) = 'B':(pv x) pv (_:x) = pv x
-- can that be a list comprehension, like
pv s = [ 'A' | A <- s -- ?? ]
thanks, Donn
You basically want map and filter. Moreover, you are also inlining a toChar function which complicates matters.
If you have ‘Eq V’ instance and ‘toChar’ function then you could write it as
[ toChar y | y <- [ x | x <- s, x /= C ] ]
Where inner comprehension is just filter and outer is just map. It doesn't make much sense to do it this way and it imposes an extra constraint, Eq. Alternative (with LambdaCase):
map toChar $ filter (\case { C -> False; _ -> True }) s
But that's ugly and we still need toChar. Further, although not really applicable here, there might not be a reasonable toChar :: V -> Char for every constructor of V.
Oh, forgot to mention one thing. You could have a toChar :: V -> Maybe Char and have a comprehension like [ y | Just y <- [ toChar x | x <- s, x /= C ] ] a.k.a. mapMaybe toChar . filter (/= C) and without Eq mapMaybe toChar . filter (\case { C -> False; _ -> True }) but we still need to write toChar separately and the comprehension still has Eq constraint. Of course we could inline the pattern match and so on but in the end it's all just ugly. Stick to what you have.
So in conclusion, the way you have now is pretty good: it avoids Eq constraint and it doesn't force us to write (possibly partial) toChar.
So to answer your question, no, you can't extend this very easily to multiple without effectively inlining your existing ‘pv’ function into the comprehension.
-- Mateusz K.