Finding a single element in a list using list comprehension - haskell

The function valueOf gets the Int value of the corresponding String out of a tuple list.
Can someone explain how the third line works?
type State = [(String,Int)]
valueOf :: State -> String -> Int
valueOf xs var = head [b | (a,b) <- xs , a ==var ]
I've never seen a Haskell expression like that, I'm more used to expression like this:
(\xs -> length xs > 15)

There is no lambda expression. What you are seeing is a list comprehension, which is a way of creating a list of values satisfying a certain condition.
In this case the comprehension [b | (a,b) <- xs , a ==var ] means something like: create a list of all bs such that (a, b) is an element of list xs, where a is equal to var.
In imperative pseudo-code you could write it as
result = EMPTY_LIST
for (a,b) in xs:
if a == var:
result.add(b)
return result
So, the whole valueOf function works by generating a list of values that have the right String key, and then uses head function to get the first one. Note that if there is no match, the whole computation will crash.

(a,b) <- xs is not a lambda, it is a generator in a list comprehension
In this case it successively binds the pairs in the source list xs and matches them with (a, b). The boolean guard a == var retains all elements for which a == var is true.

The line
valueOf xs var = head [b | (a,b) <- xs , a ==var ]
is equivalent to the lambda expression
valueOf = \xs var -> head [b | (a,b) <- xs , a ==var ]
However, I guess that what really confuses you is the list comprehension [b | (a,b) <- xs , a ==var ]. This expression builds a list as follows: loop over all the pairs in xs (this is the part (a,b)<-xs), keep only those pairs where a==var, then take all the remaining b and build a list with those.
With head in front, this will simply look in xs for the first pair whose first component is var, and return its second component. If no such pair is found, a runtime error will be generated (unless xs is an infinite list, which will cause the program to run forever).

Related

How does listx2 = [x * 2 | x<- numberList] work?

So I m watching a very basic Tutorial, and I m at list comprehension where this comes up:
listx2 = [x * 2 | x<- numberList]
with numberList being a list of numbers
So this takes every number in the list and duplicates it, so numberList = [1,2] results in [2,4].
But HOW does the whole Syntax come together?
I know that x * 2 is the doubleing, but the rest just doesn't make sense to me.
| is the "or" Symbol as far as I know,and what does it do there?
x <- numberList gives x a number from the list, but why does it take just a number? and why so nicely one after the other? There is no recursion or anything that tells it to do one element at a time...
I learn stuff by understanding it, so is that even possible here or do I just have to accept this as "thats how it goes" and memorize the pattern?
List comprehensions use their own special syntax, which is
[ e | q1, q2, ..., qn ]
The | is not an "or", it's part of the syntax, just as [ and ].
Each qi can be of the following forms.
x <- list chooses x from the list
condition is a boolean expression, which discards the xs chosen before if the condition is false
let y = expression defines variable y accordingly
Finally, e is an expression which can involve all the variables defined in the qi, and which forms the elements in the resulting list.
What you see is syntactical sugar. So Haskell does not interpret the pipe (|) as a guard, etc. It sees the list comprehension as a whole.
This however does not mean that the <- are picked at random. Actually list comprehension maps nicely on the list monad. What you see is syntactical sugar for:
listx2 = do
x <- numberList
return x*2
Now a list type [] is actually a monad. It means that we have written:
listx2 = numberList >>= \x -> return (x*2)
Or even shorter:
listx2 = numberList >>= return . (*2)
Now the list monad is defined as:
instance Monad [] where
return x = [x]
xs >>= k = concat $ fmap k xs
So this means that it is equivalent to:
listx2 = numberList >>= return . (*2)
listx2 = concat (fmap (return . (*2)) numberList)
listx2 = concat (fmap (\x -> [2*x]) numberList)
Now for a list fmap is equal to map, so:
listx2 = concat $ map (\x -> [2*x]) numberList
listx2 = concatMap (\x -> [2*x]) numberList
so that means that for every element x in the numberList we will generate a singleton list [2*x] and concatenate all these singleton lists into the result.

Swapping Pairs in Haskell

So i've got this function to swap pairs of numbers in haskell, and i don't know what i've done wrong, maybe you guys can give me a hand.
SO basically this function gets a list, say, [1,2,3,4,5], and returns the numbers swapped by pairs, something like, [2,1,4,3,5]. if the number of elements is odd, the last element stays the same.
Here's what i've done:
swapPairs :: [a] -> [a]
swapPairs (x:xs) = [!!x = !!x+1 && !!x+1 = !!x| x <- xs]
-- Return first two elements in inverted order, recusively call for remaining list,
-- only matches lists of two or more elements
swapPairs (a:b:xs) = b : a : swapPairs xs
-- Return tail for zero or one remaining elements
swapPairs (xs) = xs
You can use pattern matching to fetch 2 head elements:
swapPairs (x:y:xs) = y : x : (swapPairs xs)

mapping over entire data set to get results

Suppose I have the arrays:
A = "ABACUS"
B = "YELLOW"
And they are zipped so: Pairing = zip A B
I also have a function Connect :: Char -> [(Char,Char)] -> [(Char,Char,Int)]
What I want to do is given a char such as A, find the indices of where it is present in the first string and return the character in the same positions in the second string, as well as the position e.g. if I did Connect 'A' Pairing I'd want (A,Y,0) and (A,L,2) as results.
I know I can do
pos = x!!map fst pairing
to retrieve the positions. And fnd = findIndices (==pos) map snd pairing to get what's in this position in the second string but in Haskell how would I do this over the whole set of data (as if I were using a for loop) and how would I get my outputs?
To do exactly as you asked (but correct the initial letter of function names to be lowercase), I could define
connect :: Char -> [(Char,Char)] -> [(Char,Char,Int)]
connect c pairs = [(a,b,n)|((a,b),n) <- zip pairs [0..], a == c]
so if
pairing = zip "ABACUS" "YELLOW"
we get
ghci> connect 'A' pairing
[('A','Y',0),('A','L',2)]
However, I think it'd be neater to zip once, not twice, using zip3:
connect3 :: Char -> String -> String -> [(Char,Char,Int)]
connect3 c xs ys = filter (\(a,_,_) -> a==c) (zip3 xs ys [0..])
which is equivalent to
connect3' c xs ys = [(a,b,n)| (a,b,n) <- zip3 xs ys [0..], a==c]
they all work as you wanted:
ghci> connect3 'A' "ABACUS" "YELLOW"
[('A','Y',0),('A','L',2)]
ghci> connect3' 'A' "ABACUS" "AQUAMARINE"
[('A','A',0),('A','U',2)]
In comments, you said you'd like to get pairs for matches the other way round.
This time, it'd be most convenient to use the monadic do notation, since lists are an example of a monad.
connectEither :: (Char,Char) -> String -> String -> [(Char,Char,Int)]
connectEither (c1,c2) xs ys = do
(a,b,n) <- zip3 xs ys [0..]
if a == c1 then return (a,b,n) else
if b == c2 then return (b,a,n) else
fail "Doesn't match - leave it out"
I've used the fail function to leave out ones that don't match. The three lines starting if, if and fail are increasingly indented because they're actually one line from Haskell's point of view.
ghci> connectEither ('a','n') "abacus" "banana"
[('a','b',0),('a','n',2),('n','u',4)]
In this case, it hasn't included ('n','a',2) because it's only checking one way.
We can allow both ways by reusing existing functions:
connectBoth :: (Char,Char) -> String -> String -> [(Char,Char,Int)]
connectBoth (c1,c2) xs ys = lefts ++ rights where
lefts = connect3 c1 xs ys
rights = connect3 c2 ys xs
which gives us everything we want to get:
ghci> connectBoth ('a','n') "abacus" "banana"
[('a','b',0),('a','n',2),('n','a',2),('n','u',4)]
but unfortunately things more than once:
ghci> connectBoth ('A','A') "Austria" "Antwerp"
[('A','A',0),('A','A',0)]
So we can get rid of that using nub from Data.List. (Add import Data.List at the top of your file.)
connectBothOnce (c1,c2) xs ys = nub $ connectBoth (c1,c2) xs ys
giving
ghci> connectBothOnce ('A','A') "ABACUS" "Antwerp"
[('A','A',0),('A','t',2)]
I would recommend not zipping the lists together, since that'd just make it more difficult to use the function elemIndices from Data.List. You then have a list of the indices that you can use directly to get the values out of the second list.
You can add indices with another zip, then filter on the given character and convert tuples to triples. Especially because of this repackaging, a list comprehension seems appropriate:
connect c pairs = [(a, b, idx) | ((a, b), idx) <- zip pairs [0..], a == c]

Breaking down a haskell function

I'm reading Real world haskell book again and it's making more sense. I've come accross this function and wanted to know if my interpretation of what it's doing is correct. The function is
oddList :: [Int] -> [Int]
oddList (x:xs) | odd x = x : oddList xs
| otherwise = oddList xs
oddList _ = []
I've read that as
Define the function oddList which accepts a list of ints and returns a list of ints.
Pattern matching: when the parameter is a list.
Take the first item, binding it to x, leaving the remainder elements in xs.
If x is an odd number prepend x to the result of applying oddList to the remaining elements xs and return that result. Repeat...
When x isn't odd, just return the result of applying oddList to xs
In all other cases return an empty list.
1) Is that a suitable/correct way of reading that?
2) Even though I think I understand it, I'm not convinced I've got the (x:xs) bit down. How should that be read, what's it actually doing?
3) Is the |...| otherwise syntax similar/same as the case expr of syntax
1 I'd make only 2 changes to your description:
when the parameter is a nonempty list.
f x is an odd number prepend x to the result of applying oddList to the remaining elements xs and return that result. [delete "Repeat...""]
Note that for the "_", "In all other cases" actually means "When the argument is an empty list", since that is the only other case.
2 The (x:xs) is a pattern that introduces two variables. The pattern matches non empty lists and binds the x variable to the first item (head) of the list and binds xs to the remainder (tail) of the list.
3 Yes. An equivalent way to write the same function is
oddList :: [Int] -> [Int]
oddList ys = case ys of { (x:xs) | odd x -> x : oddList xs ;
(x:xs) | otherwise -> oddList xs ;
_ -> [] }
Note that otherwise is just the same as True, so | otherwise could be omitted here.
You got it right.
The (x:xs) parts says: If the list contains at least one element, bind the first element to x, and the rest of the list to xs
The code could also be written as
oddList :: [Int] -> [Int]
oddList (x:xs) = case (odd x) of
True -> x : oddList xs
False -> oddList xs
oddList _ = []
In this specific case, the guard (|) is just a prettier way to write that down. Note that otherwise is just a synonym for True , which usually makes the code easier to read.
What #DanielWagner is pointing out, is we in some cases, the use of guards allow for some more complex behavior.
Consider this function (which is only relevant for illustrating the principle)
funnyList :: [Int] -> [Int]
funnyList (x1:x2:xs)
| even x1 && even x2 = x1 : funnyList xs
| odd x1 && odd x2 = x2 : funnyList xs
funnyList (x:xs)
| odd x = x : funnyList xs
funnyList _ = []
This function will go though these clauses until one of them is true:
If there are at least two elements (x1 and x2) and they are both even, then the result is:
adding the first element (x1) to the result of processing the rest of the list (not including x1 or x2)
If there are at least one element in the list (x), and it is odd, then the result is:
adding the first element (x) to the result of processing the rest of the list (not including x)
No matter what the list looks like, the result is:
an empty list []
thus funnyList [1,3,4,5] == [1,3] and funnyList [1,2,4,5,6] == [1,2,5]
You should also checkout the free online book Learn You a Haskell for Great Good
You've correctly understood what it does on the low level.
However, with some experience you should be able to interpret it in the "big picture" right away: when you have two cases (x:xs) and _, and xs only turns up again as an argument to the function again, it means this is a list consumer. In fact, such a function is always equivalent to a foldr. Your function has the form
oddList' (x:xs) = g x $ oddList' xs
oddList' [] = q
with
g :: Int -> [Int] -> [Int]
g x qs | odd x = x : qs
| otherwise = qs
q = [] :: [Int]
The definition can thus be compacted to oddList' = foldr g q.
While you may right now not be more comfortable with a fold than with explicit recursion, it's actually much simpler to read once you've seen it a few times.
Actually of course, the example can be done even simpler: oddList'' = filter odd.
Read (x:xs) as: a list that was constructed with an expression of the form (x:xs)
And then, make sure you understand that every non-empty list must have been constructed with the (:) constructor.
This is apparent when you consider that the list type has just 2 constructors: [] construct the empty list, while (a:xs) constructs the list whose head is a and whose tail is xs.
You need also to mentally de-sugar expressions like
[a,b,c] = a : b : c : []
and
"foo" = 'f' : 'o' : 'o' : []
This syntactic sugar is the only difference between lists and other types like Maybe, Either or your own types. For example, when you write
foo (Just x) = ....
foo Nothing = .....
we are also considering the two base cases for Maybe:
it has been constructed with Just
it has been constructed with Nothing

Haskell building a list of tuples

I am trying to build a list of tuples. Input is a list of tuples [([char], int1, int2), ...] and the output is the list of tuples such that [([char], int1, int2, (int1/int2)), ...]. I know that this code below is wrong because I think it is building a list of lists of tuples [[(),(),(),()], [(),(),(),()]].
Code:
{- take a list of labels, values, and weights and return list of labels and fractions -}
fraclist [] = []
fraclist x = [ (y,r,q,z) : y <- first (head x) | r <- scnd (head x) | q <- last (head x) | z <- r/q ] : fraclist tail x
{- helper func to get values from tuples -}
frst (a,b,c) = a
scnd (a,b,c) = b
last (a,b,c) = c
How might I get the proper output form as described? Also, how might I output the list of tuples ordered such that the z's are in descending order?
This code doesn't compile (syntax errors), but after fixing that (I'd recommend reading up on the syntax of list comprehensions (','s vs. '|'s)) and making some other changes:
used a list comprehension, which takes care of the base case and the mapping over the list -- so I was able to eliminate fraclist [] = [] and the head/tail/: business
used pattern matching to pull the values out of the input tuples -- this is often much easier to read than using functions to take apart values
added an explicit type signature for documentation purposes
here's what I think you meant:
fraclist :: (Integral t1) => [(t, t1, t1)] -> [(t, t1, t1, t1)]
fraclist xs = [(x, y, z, div y z) | (x, y, z) <- xs]
I'll leave the sorting to you.
I think you want just
fraclist xs = [(y,r,q, r `quot` q) | (y,r,q) <- xs]
(Note: I used quot instead of (/) since you named the components int1, int2.)
A variant not using list comprehensions is
fraclist = map (\(y,r,q) -> (y,r,q, r `quot` q))
Your code doesn't compile, in such cases it is better to post the error message so people can see at one glance what the probable cause is.
You get a parse erro on the first <- in
fraclist x = [ (y,r,q,z) : y <- first (head x) | r <- scnd (head x) | q <- last (head x) | z <- r/q ] : fraclist tail x
because the expression (y,r,q,z) : y <- first (head x) before the first | separating the generated expressions from the generator expressions isn't well-formed. I think it's just a typo and you meant to use | instead of (:) there too.
Then you have several | separators in your list comprehension, which is not valid without the ParallelListComp extension. However, the code doesn't look like a parallel list comprehension is really what you attempt here, since all three values are drawn from the same list. Finally, the last part | z <- r/q is again not well-formed, since r/q is not a list from which elements can be drawn in a list comprehension. You probably intended let z = r/q there.
Here is a simple solution without list comprehension:
import Data.List
-- (string, int1, int2) -> (string int1, int2, (int1/int2))
fraclist list = map generateTuple list
where generateTuple (label, value, weight) = (label, value, weight, (value)/(weight))
sortFracListByValueWeightRatio list = sortBy sorter list
where sorter (_,_,_,d) (_,_,_,h) = if d > h then GT else LT
testList = [("first",3.0,4.0), ("second",4.0,7.0)]
Nothing fancy (I've only used haskell a week).
fraclist works by mapping the generateTuple function to the list. The generateTuple function simply returns a tuple of form (title, value, weight, value/weight). Map is a built in function which simply applies a given function to each element of the list.
The sortFracListByValueWeightRatio (sorry for the long name) uses the built in sortBy function (comes from Data.List), which sorts a given list using a custom function for comparing items. Sorter is my item comparer, and it simply compares the value/weight ratios and returns either GT or LT (Greater Than / Lower Than). Hence, the list items are compared using the custom comparer, and sorted based on its answer.
A significant improvement of readability would probably be to use types to describe the values instead of just tuples. Also I'm using doubles in the test list, but that is easy to change.

Resources