Reputation: 73
a Haskell newby, so apologies if this is a rather basic question. I want to write a function which takes two lists of variables and returns the first with all variables from the second list removed from it. For example I want the following output
*Main> filterVariables ["y","z","a1","a2"] ["y","a1","a3"]
["z","a2"]
This what I have written so far:
type Var = String
data Term =
Variable Var
| Lambda Var Term
| Apply Term Term
variables :: [Var]
variables = [l:[] | l <- ['a'..'z']] ++ [l:show x | x <- [1..], l <- ['a'..'z']]
--works but the wrong way around!!!
filterVariables :: [Var] -> [Var] -> [Var]
filterVariables lst = filter ( `notElem` lst)
I get the following ouput:
*Main> filterVariables ["y","z","a1","a2"] ["y","a1","a3"]
["a3"]
Could the flip function be used here?
When I write:
filterVariables lst = flip (filter ( `notElem` lst))
I get this error message:
Couldn't match type ‘[Var]’ with ‘[Var] -> c0’
Expected type: [Var] -> [Var] -> c0
Actual type: [Var] -> [Var]
• Possible cause: ‘filter’ is applied to too many arguments
In the first argument of ‘flip’, namely ‘(filter (`notElem` lst))’
In the expression: flip (filter (`notElem` lst))
In an equation for ‘filterVariables’:
filterVariables lst = flip (filter (`notElem` lst))
How do I use flip correctly? Or can you suggest another method?
Upvotes: 1
Views: 518
Reputation: 153132
The flip
function takes an argument function of two inputs. So if you want to flip the arguments to filterVariables
, you have to flip
it in a form that takes two arguments. In your version:
filterVariables lst = flip (filter ( `notElem` lst))
you have already accepted one argument, and only one remains to accept. We can fix this by first moving the lst
argument to the other side of the equality:
filterVariables lst = filter ( `notElem` lst) -- original, accepts one more argument
filterVariables = \lst -> filter (`notElem` lst) -- now a function which accepts two arguments
filterVariables = flip (\lst -> filter (`notElem` lst)) -- flipped form
Upvotes: 2
Reputation: 477240
I think it might be simpler to write this as:
filterVariables :: Eq => [a] -> [a] -> [a]
filterVariables items lst = filter (`notElem` lst) items
You can not flip
on filter (`notElem` lst)
since, filter (
notElemlst)
has type [a] -> [a]
, and flip
has type flip :: (b -> a -> c) -> a -> b -> c
. This thus should mean that [a] -> [a]
is the same type as b -> a -> c
, but that implies that [a]
and a -> c
are the same type.
You can however make use of flip
by implementing a point-free variant:
filterVariables :: (Foldable t, Eq a) => [a] -> t a -> [a]
filterVariables =flip (filter . flip notElem)
Indeed, here filter . flip notElem
has type filter . flip notElem :: (Eq a, Foldable t) => t a -> [a] -> [a]
since it is equivalent to \xs ys -> filter (flip notElem xs) ys
or shorter \xs -> filter (`notElem` xs)
, so we can then flip xs
and ys
.
Upvotes: 0