danish sodhi
danish sodhi

Reputation: 1913

Understanding haskell code

I am new to haskell. Can someone explain how I can interpret this line of code in haskell :

filter (\(_, (varible1, _)) -> variable1 `notElem` [something1, something2])

Upvotes: 1

Views: 159

Answers (2)

Carcigenicate
Carcigenicate

Reputation: 45726

-- Filter a list...
filter

-- ...of nested tuples where the first element of the second element of the tuple...
(\(_, (variable1, _)) ->

-- ...is not an element of [something1, something2]
variable1 `notElem` [something1, something2]) 

(_, (varible1, _)) deconstructs a nested tuple, and names one of the elements. Look up deconstruction to understand what's going on there.

Upvotes: 6

Rein Henrichs
Rein Henrichs

Reputation: 15605

Let's start at the beginning.

\p -> e

is a lambda abstraction (an anonymous function) where p is a pattern and e is an expression that may use variables that appear in p.

(_, (variable1, _))

is a pattern constructed from the constructor (,), which constructs pairs. Here are some pairs:

(1, 2)
("Hello", "world!")
(1, (2, 3))

Here are some patterns which match pairs, used in lambda abstractions.

\(x, y) -> x
\(x,(y,z)) -> y

The second pattern matches a pair like (1, (2, 3)) and gives the first element of the second element. In this case, it would give 2. Its shape is like the pattern in your question, but what about the _ in your pattern?

_ is a valid variable name (variables can begin with underscores or lower-case letters). It is used to mean "a variable we don't use". The pattern (_, (y, _)) is like the pattern (x, (y, z)) except the only variable that has a name is y. Normally, you aren't allowed to reuse variable names in patterns. (x,x) is in invalid pattern, for instance. You are allowed to reuse _ though because Haskell knows you intend to throw that value away.

Now we can understand the expression

\(_, (variable1, _)) -> variable1

It is a function of type (a, (b, c)) -> b which takes a pair whose second element is itself a pair and gives the first element of the second element.

Now we need to understand

variable1 `notElem` [something1, something2]

To understand this expression, we need to know what the backticks do. Surrounding an identifier in backticks turns it into an infix operator. Infix operators are usually spelled with symbols, like x + y and xs ++ ys. The backticks let us convert normal identifiers, like notElem, into infix operators. This means that the above expression is the same as

notElem variable1 [something1, something2]

notElem is a function which takes an item and a list of items of the same type and gives True if the item does not appear in the list and False otherwise. It is the opposite of the elem test for membership.

Finally, filter. filter p xs is a function that takes a predicate p (i.e., a function which returns a Bool) and uses it to filter the list xs. filter gives a new list where elements (call them x) are included if p x is true. This filters the list of xs and gives a new list whose elements are those for which the predicate is true. For example,

> filter even [1,2,3,4]
[2,4]

So, we have

filter                  -- filter a list
  (\(_, (variable1, _)) -- by matching on the first element
                        -- of the second element of a pair
                        -- and calling it 'variable1'
     -> variable1 `notElem` [something1, something2])
                        -- and giving `True` if the element
                        -- is neither 'something1' nor 'something2'

This gives a function which takes a list of pairs whose second element is a pair and filters it to a list of pairs whose second element is a pair whose first element is neither something1 nor something2.

We can apply it, calling it f below:

f = filter (\(_, (varible1, _)) -> variable1 `notElem` [something1, something2])

> f [(1,(something1,2)), (1,(something3,3))]
[(1,(something3,3))]

Upvotes: 5

Related Questions