I have functions defined as follows:
distance3 :: String -> String -> Float
distance3 x y = fromIntegral $ abs $ length x - length y
distanceFilter :: (String -> String -> Float) -> Float -> String
-> [String] -> [String]
distanceFilter f d s ss = filter (\x -> f s x <= d) ss
The distanceFilter returns all the strings in ss that are at most d distance away from s.
It works as it is supposed to, but I have trouble understanding the inner workings of
filter (\x -> f s x <=d) ss
Obviously the \x -> takes a string from the list ss and applies it to the function f as the second parameter, but how does it do that? How does it know how to take the element? How does that lambda expression work?
CodePudding user response:
\x -> f s x <= d
constructs a function that takes a string and returns a Bool
, it thus has type String -> Bool
. It is equivalent to defining a function go
like:
go :: String -> Bool
go x = f s x <= d
and thus calling this function go
as filter predicate.
filter
will call the predicate on all items. It is implemented as [src]:
filter :: (a -> Bool) -> [a] -> [a] filter _pred [] = [] filter pred (x:xs) | pred x = x : filter pred xs | otherwise = filter pred xs
For an empty list it thus returns an empty list, and for a non-empty list, it calls pred
with x
as parameter, and if the predicate returns True
, it yields x
. In both cases it recurses on the rest of the list.
So the filter calls the predicate with the elements of the list, and since the lambda expression thus is a function that takes such parameter as input, it can be used to determine whether it should yield an element x
or not.
CodePudding user response:
distanceFilter f d s ss = filter (\x -> f s x <= d) ss
There are two separate aspects to your question:
The lambda "closes" over the values from the outer scope. In this case,
f
,s
andd
in(\x -> f s x <= d)
refer to the parameters of the function and get their values from the arguments that are passed in. This is called a "closure". You can do some more research on your own to understand more deeply.filter
determines what values are passed asx
to the lambda. By definition,filter f xs
applies the functionf
to each element of the listxs
. Sox
in your lambda will be each element ofss
in turn. Implementing your own version offilter
is a great exercise to understand how it works.