Meaning of backslash in Haskell code? - haskell

So I have this haskell code, and I understand half of it, but I can't get my head around this \x -> here:
testDB :: Catalogue
testDB = fromList [
("0265090316581", ("The Macannihav'nmor Highland Single Malt", "75ml bottle")),
("0903900739533", ("Bagpipes of Glory", "6-CD Box")),
("9780201342758", ("Thompson - \"Haskell: The Craft of Functional Programming\"", "Book")),
("0042400212509", ("Universal deep-frying pan", "pc"))
]
-- Exercise 1
longestProductLen :: [(Barcode, Item)] -> Int
longestProductLen = maximum . map (\(x, y) -> length $ fst y)
formatLine :: Int -> (Barcode, Item) -> String
formatLine k (x, (y1, y2)) = x ++ "..." ++ y1 ++ (take (k - length y1) (repeat '.')) ++ "..." ++ y2
showCatalogue :: Catalogue -> String
showCatalogue c = foldr (++) "" $ map (\x -> (formatLine (longestProductLen (toList testDB)) x) ++ "\n") $ toList c
I understand that longestProductLen returns and integer meaning the longest title in testDB and then it uses this integer to match k in formatLine, but I can't understnad how it matches (Bardcode, Item) and I guess it has something to do with \x ->, if it does can you please explain how it does that?
Thank you!

The syntax
function x y = <body>
Is equivalent to
function = \x y -> <body>
And is called a lambda or anonymous function. The compiler actually turns all your functions into assignments of lambda functions (the second form) since it's just giving a function value (functions are values in Haskell) a name.
If you see it given as an argument to another function like map:
map (\x -> x + 1) [1, 2, 3]
This is semantically equivalent to
map add1 [1, 2, 3] where add1 x = x + 1
Lambdas can perform arbitrary pattern matching on their arguments, too. Also, if you have a definition like
fib 0 = 1
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)
This is equivalent to
fib = \n -> case n of
0 -> 1
1 -> 1
n -> fib (n - 1) + fib (n - 2)
Because the compiler will first translate the multiple pattern matching into a case statement, then convert it to assigning a lambda to a name (in this case assigning the lambda to the name fib).

That's Haskell's syntax for lambda abstraction. The Haskell
\x -> e
corresponds to the mathematical
λx.e
In this case,
\(x, y) -> length $ fst y
is a function that takes a pair (x,y) and returns the length of the first component of the pair y. This is a slightly odd way to write the expression; it would be better to write it as
\(x, (y1, y2)) -> length y1
or as
length . fst . snd
for consistency.

Related

Haskell naive duplicate filtering

I do not understand a sample solution for the following problem: given a list of elements, remove the duplicates. Then count the unique digits of a number. No explicit recursion may be used for either problem.
My code:
removeDuplicates :: Eq a => [a] -> [a]
removeDuplicates = foldr (\x ys -> x:(filter (x /=) ys)) []
differentDigits :: Int -> Int
differentDigits xs = length (removeDuplicates (show xs))
The solution I am trying to understand has a different definition for differentDigits, namely
differentDigits xs = foldr (\ _ x -> x + 1) 0 ( removeDuplicates ( filter (/= '_') ( show xs )))
Both approaches work, but I cannot grasp the sample solution. To break my question down into subquestions,
How does the first argument to filter work? I mean
(/= '_')
How does the lambda for foldr work? In
foldr (\ _ x -> x + 1)
^
the variable x should still be the Char list? How does Haskell figure out that actually 0 should be incremented?
filter (/= '_') is, I'm pretty sure, redundant. It filters out underscore characters, which shouldn't be present in the result of show xs, assuming xs is a number of some sort.
foldr (\ _ x -> x + 1) 0 is equivalent to length. The way foldr works, it takes the second argument (which in your example is zero) as the starting point, then applies the first argument (in your example, lambda) to it over and over for every element of the input list. The element of the input list is passed into the lambda as first argument (denoted _ in your example), and the running sum is passed as second argument (denoted x). Since the lambda just returns a "plus one" number on every pass, the result will be a number representing how many times the lambda was called - which is the length of the list.
First, note that (2) is written in so called point free style, leaving out the third argument of foldr.
https://en.wikipedia.org/wiki/Tacit_programming#Functional_programming
Also, the underscore in \_ x -> x + 1 is a wild card, that simply marks the place of a parameter but that does not give it a name (a wild card works as a nameless parameter).
Second, (2) is a really nothing else than a simple recursive function that folds to the right. foldr is a compact way to write such recursive functions (in your case length):
foldr :: (a -> b -> b) -> b -> [a]
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
If we write
foldr f c ls
ls is the list over which our recursive function should recur (a is the type of the elements).
c is the result in the base case (when the recursive recursive function is applied on an empty list).
f computes the result in the general case (when the recursive function is applied on a non-empty list). f takes two arguments:
The head of the list and
the result of the recursive call on the tail of the list.
So, given f and c, foldr will go through the list ls recursively.
A first example
The Wikipedia page about point free style gives the example of how we can compute the sum of all elements in a list using foldr:
Instead of writing
sum [] = 0
sum (x:xs) = x + sum xs
we can write
sum = foldr (+) 0
The operator section (+) is a 2-argument function that adds its arguments. The expression
sum [1,2,3,4]
is computed as
1 + (2 + (3 + (4)))
(hence "folding to the right").
Example: Multiplying all elements.
Instead of
prod [] = 1
prod (x:xs) = x * prod xs
we can write
prod = foldr (*) 1
Example: Remove all occurrences of a value from a list.
Instead of
remove _ [] = []
remove v (x:xs) = if x==v then remove v xs else x:remove v xs
we can write
remove v = foldr (\x r -> if x==v then r else x:r) []
Your case, (2)
We can now fully understand that
length = foldr (\ _ x -> x + 1) 0
in fact is the same as
length [] = 0
length (x:xs) = length xs + 1
that is, the length function.
Hope this recursive view on foldr helped you understand the code.

Haskell list of list's

I want to compare each item in the list of lists with other elements, for example,
[[1,2,3], [0,2,2], [1,4,5], [3,1,1]]
compare [1,2,3] to [0,2,2] and applying an operation (for example, the formula of distance "sqrt ((x2-x1)^2+(y2-y1)^2)" and the result of that operation evaluate it with a guard), then compare the [1,2,3] to [1,4,5] and so end the list, then with [0 , 2.2] to [1,4,5] etc ...
I was thinking about taking (head i) and tail (head i) to compare, but do not know how to continue iterating comparisons
can you guys give me an idea about how i can do this? thank you
edit
what i need is this, with the first list of list i need to make another list of list's based on the distance formula and comparing the 3rd element of the list, for example
[[1,2,3], [0,2,2], [1,4,5], [3,1,1]]
[x1,y1,z1], [x2,y2,z2]
sqrt ((x2-x1)^2+(y2-y1)^2)) if result_of_sqrt < z1 then 1:[do the same thing with the other element]
else 0:[do the same thing with the other element]
sqrt ((0-1)^2+(2-2)^2) ) = 1, 1 < 3 => 1:(compare this two elements [1,2,3],[1,4,5]) and so...
The question is really unclear, but it sounds like, at a fundamental level, you want to take each element of a list and compare it to all of the rest of elements in the list. Say we want to pair all of the elements in [1..3] where order doesn't matter, i.e. we want the list:
`[(1, 2), (1, 3), (2, 3)]`
We can do this directly:
pairAll :: [a] -> [(a, a)]
pairAll [] = []
pairAll (x:xs) = map (\y -> (x, y)) xs ++ pairAll xs
Now pairAll [1..3] == [(1, 2), (1, 3), (2, 3)] as desired. We can factor out the pairing function to get:
doStuffToAll :: (a -> a -> b) -> [a] -> [b]
doStuffToAll _ [] = []
doStuffToAll f (x:xs) = map (f x) xs ++ doStuffToAll f xs
And then pairAll = doStuffToAll (\x y -> (x, y)).
Replace the lambda expression with your comparison function for lists (i.e. doStuffWithAll compareLists), and that should do it, if I understand your question properly.
This seems to produce your last example result:
f xs = map (\x -> map (test x) xs) xs
where test a#[x1,y1,z1] b#[x2,y2,z2] =
if a == b
then 0
else if sqrt ((x2 - x1) ^ 2 + (y2 - y1) ^ 2) < z1
then 1
else 0
Or with guards instead of if and else:
f xs = map (\x -> map (test x) xs) xs
where test a#[x1,y1,z1] b#[x2,y2,z2]
| a == b = 0
| m < z1 = 1
| otherwise = 0
where m = sqrt ((x2 - x1) ^ 2 + (y2 - y1) ^ 2)
Output:
*Main> f [[0,0,4], [2,4,2], [1,3,5], [3,1,1]]
[[0,0,1,1],[0,0,1,0],[1,1,0,1],[0,0,0,0]]
I'm not sure if I've understood you correctly, but perhaps this will help you figure something out:
Pair up all the tuples
Apply your 'comparison' function to those tuples and output a true/false
.
lol :: [(Int,Int,Int)]
lol = [(1,2,3), (0,2,2), (1,4,5), (3,1,1)]
-- Use list comprehension to get all your unique pairs
tuples = [(x,y) | x <- lol, y <- lol, x > y]
result = map myCompare tuples
-- myCompare takes a tuple of two 3-vector tuples and does an operation on them
-- It outputs the two vectors it and a True/False
myCompare (x#(x1,y1,z1),y#(x2,y2,z2)) = if ( (x1-x2)^2 + (y1-y2)^2 < (z2-z1)^2 ) then (x,y,True) else (x,y,False)
Outputs:
tuples = [((1,2,3),(0,2,2)),((1,4,5),(1,2,3)),((1,4,5),(0,2,2)),((3,1,1),(1,2,3)),((3,1,1),(0,2,2)),((3,1,1),(1,4,5))]
result = [((1,2,3),(0,2,2),False),((1,4,5),(1,2,3),False),((1,4,5),(0,2,2),True),((3,1,1),(1,2,3),False),((3,1,1),(0,2,2),False),((3,1,1),(1,4,5),True)]

Function to Shrink a List By ONE Haskell

Trying to return a list with the last element removed. Why am I getting this error?
ERROR file:.\ShrinkByOne.hs:5 - Type error in application
*** Expression : (lis !! n : result) lis n
*** Term : (:)
*** Type : f -> [f] -> [f]
*** Does not match : a -> b -> c -> d -> e
shrinkByOne :: [Int] -> [Int] -> Int -> [Int]
shrinkByOne result lis n
| n <= ((length lis) - 2) = shrinkByOne ( ((lis !! n):result) lis n+1) -- this condition prevents the last element from being returned
| otherwise = result
Why the error?
In your original code, you had something like that:
shrinkByOne (... something ...)
which meant that you applied only one argument to shrinkByOne. You need this instead:
shrinkByOne (... something ...) (... something ...) (... something ...)
Therefore, put parentheses this way:
shrinkByOne :: [Int] -> [Int] -> Int -> [Int]
shrinkByOne result lis n
| n <= ((length lis) - 2) = shrinkByOne ((lis !! n):result) lis (n+1) -- this condition prevents the last element from being returned
| otherwise = result
Other remarks
However, you will still not get the desired result, as the result will be reversed and the !! is expensive, and your function will be of Θ(n²) complexity.
Try a much simpler, linear approach:
shrinkByOne' :: [Int] -> [Int]
shrinkByOne' [x] = []
shrinkByOne' (x : xs) = x : shrinkByOne' xs
Finally, I understand that this is an exercise to learn Haskell. If it's not, simply use the init function from the Prelude.
First, you want to leave out unneeded parens around function arguments. f(x) is written f x in Haskell (that one's just optional), and in particular you can't write g (x y) if g :: A -> B -> C, it needs to be g x y (or possibly g (x) (y). But g (x y) would mean, you apply the function x to the argument y, and use the result as argument for g. (If you actually want that, write g $ x y, or g . x $ y.)
So that would mean shrinkByOne ((lis !! n):result) lis n+1. Which would, however, be parsed as (shrinkByOne ((lis !! n):result) lis n) + 1: infix operators like + always have lower precedence than function application, so indeed around n+1 you do need parens.

Definiton of length using foldr

I'm trying to understand a part in the lecture notes of a class I'm taking. It defines the length function as:
length = foldr (\_ n -> 1 + n) 0
Can someone explain me how this works? I can't wrap my mind around it.
First, type of foldr: (a -> b -> b) -> b -> [a] -> b
Taking the usage into context, foldr takes in 3 arguments: a function (that takes in a. an element of a list and b. an accumulator, and returns the accumulator), the starting value of accumulator, and a list. foldr returns the final result of the accumulator after applying the function through the list.
As for this piece of code:
length = foldr (\_ n -> 1 + n) 0
As you can see, it is missing the list - so the return value of the right hand side is a function that will take in a list and produce an Int (same type as 0). Type: [a] -> Int.
As for what the right hand side means: (\_ n -> 1 + n) 0
\ means declare an unnamed function
_ means ignore the element from the list (correspond to a in the type of foldr). As you know, foldr will go through the list and apply the function to each element. This is the element passed into the function. We don't have any use of it in a length function, so we denote that it should be ignored.
n is the parameter for the Int passed in as accumulator.
-> means return
1 + n will increment the accumulator. You can imagine that the return value is passed back to foldr and foldr saves the value to pass into the next call to the function (\_ n -> 1 + n).
The 0 outside the bracket is the starting value of the counter.
The function foldr is to fold the list with a right associative operator, you can easily understand what the function does if you use the operator(+), (The function has the same behavior as sum):
foldr (+) 0 [1,2,3,4,5] = 1+(2+(3+(4+(5+0))))
For your length function, it is equivalent to:
foldr (\_ n -> 1 + n) 0 [1,2,3,4,5] = 1+(1+(1+(1+(1+0))))
That is what the foldr for
There's several equivalent ways to understand it. First one: foldr f z [1, 2, 3, 4, ..., n] computes the following value:
f 1 (f 2 (f 3 (f 4 (f ... (f n z)))))
So in your case:
length [1,2,3,4] = foldr (\_ n -> 1 + n) 0 [1,2,3,4]
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 ((\_ n -> 1 + n) 4 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 (1 + 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 (1 + (1 + 0)))
= (\_ n -> 1 + n) 1 (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + 1))
= 1 + (1 + 2)
= 1 + 3
= 4
Another one is to start from this function, which copies a list:
listCopy :: [a] -> [a]
listCopy [] = []
listCopy (x:xs) = x : listCopy xs
That may look like a trivial function, but foldr is basically just that, but except of hardcoding the empty list [] and the pair constructor : into the right hand side, we instead use some arbitrary constant and function supplied as arguments. I sometimes like to call these arguments fakeCons and fakeNil (cons and nil are the names of the : operator and [] constant in the Lisp language), because in a sense you're "copying" the list but using fake constructors:
foldr fakeCons fakeNil [] = fakeNil
foldr fakeCons fakeNil (x:xs) = fakeCons x (subfold xs)
where subfold = foldr fakeCons fakeNil
So under this interpretation, your length function is "copying" a list, except that instead of the empty list it's using 0, and instead of : it's discarding the elements and adding 1 to the running total.
And here's yet a third intepretation of foldr f z xs:
z is the solution of your problem when the list is empty.
f is a function that takes two arguments: an element of the list , and a partial solution: the solution to your problem for the list of elements that appear to the right of the element that's passed to f. f then produces a solution that's "one element bigger."
So in the case of length:
The length of an empty list is 0, so that's why you use 0 as the second argument to foldr.
If the length of xs is n, then the length of x:xs is n+1. That's what your first argument to foldr, \_ n -> n + 1, is doing: it's computing the length of a list, given as arguments the first element of the list (which in this case we ignore) and the length of the rest of the list (n).
This way of thinking about foldr is very powerful, and should not be underestimated. Basically, in the function that you pass as the first argument to foldr, you're allowed to assume that the problem you're trying to solve has already been solved for all lists shorter than the one you're dealing with. All your argument function has to do, then, is to compute an answer for a list that's one element longer.

Alternative way of creating a list than a comprehension?

Currently I am doing something like this in my code:
--Generate a list of n 'Foo's
generateFoos n = [createFoo (show i) | i <- [1..n]]
-- Create a Foo with a given name
createFoo :: String -> Foo
I was wandering if there is a another way of doing this than creating a range [1..n] all the time...
I would say don't worry about it. "Creating the range [1..n]" isn't really going on here as a distinct step; that [1..n] desugars to enumFromTo 1 n and it's constructed lazily like everything else anyway. There's no hidden cost here one would need to eliminate.
Expanding on my comment above - the reason the map function arises naturally here is as follows.
In Haskell, list comprehensions are just syntactic sugar for do notation:
[ 2 * x | x <- [1..10] ]
is equivalent to
do { x <- [1..10]; return (2 * x) }
In turn, do notation is syntactic sugar for monadic binds - the above is equivalent to
[1..10] >>= \x -> return (2 * x)
This works because List is a monad. The code that makes List into a monad is (ignoring some irrelevant stuff)
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
so the call to >>= above is equivalent to
concat (map (\x -> return (2 * x)) [1..10])
which, if we replace the call to bind, is equivalent to
concat (map (\x -> [2 * x]) [1..10])
So we map the function \x -> [2 * x] over the list [1..10] and then call concat on the result. But since our function only every builds one element lists, we can skip out the call to concat and replace the code with
map (\x -> 2 * x) [1..10]
So it's natural that relatively simple list comprehensions can be turned into expressions that involve mapping a function over a range.
I prefer it that way:
generateFoos n = map (createFoo . show) [1..n]
Or are the ranges itself the problem? Then I'd recommend:
generateFoos n = map (createFoo . show) (enumFromTo 1 n)
No map, no range.
generateFoos n = unfoldr (doit (createFoo . show)) 1 where
doit f acc = if acc > n then Nothing else Just (f acc, acc + 1)
I do not guarantee any particular quality or property of this code though ;)

Resources