Haskell List of Tuples Compare Pair - haskell

I am new to Haskell and I am trying some stuff out. I am having some trouble comparing tuples elements.
Let's say I have a tuple [(1,3),(2,1),(4,4)].
I want to compare each pair index with each other and save some data into a counter value and return that value.
For example what I want is this:
Tuple: [(a,b),(c,d),(e,f)]
When a>b I want to add 3 to the counter.
When a==b I want to add 1 to the counter.
Otherwise add 0 to the counter. Same for (c,d) and (e,f).
After iterating through my tuples I want to return the counter.
So in my example I have tuple [(1,3),(2,1),(4,4)].
The function should do
Since 1<3 add 0 to counter.
Since 2>1 add 3 to counter.
Since 4=4 add 1 to counter.
And after all return 0+3+1 = 4.
Any ideas? Thank you in advance!
(Edit)
calculateWins :: [(Int,Int)]->Int
calculateWins d ((a,b) :xs) = x
where x
|a>b = 3
|a==b = 1
|otherwise = 0

This looks like the point system of a soccer cup (and some other sports). Instead of implementing a function that calculates the sum, we better first aim to calculate something that calculates the score for one such tuple, so something like:
score :: Ord a => (a, a) -> Int
By using a as type, we can use any type of values, as long as we can compare them (the Ord type constraint). So we can write something like:
score (x, y) = -- ...
now in case x > y, then the score is 3 points, in case x == y, then the score is 1 point, and finally in case x < y (otherwise), then the score is 0 points, so we can write it as:
score :: Ord a => (a, a) -> Int
score (x, y) | x > y = 3
| x == y = 1
| otherwise = 0
So now we can perform a map score to calcuate a list of scores, and by using sum, we can calculate the sum of those points, like:
calculateWins :: Ord a => [(a, a)] -> Int
calculateWins = sum . map score

Hint: use a function of type (a -> b) -> [a] -> [b] to transform the list of tuple into a list of your summands (3 or 1 or 0), and use another function of type [a] -> a to get the sum.
The Hoogle is a very nice site for looking up Haskell functions, both by name and by signature.
Please do try these things out before simply asking for the complete code; that helps neither of us.

Related

Haskell count positive and negative numbers separately in a list

I can count number of positive occurrence with this:
count :: [Int] -> Int
count xs = length [ x | x <- xs, x > 0]
However, I can't make it work to count both positive and negative numbers.
For the input [1,2,3, -1,-2] I want (3,2) as an output. How can I achieve this?
You can work with a "fold". Here you pass a 2-tuple as "accumulator" and you increment one of the two, depending on whether the item is positive or negative.
This thus looks like:
import Data.Foldable(foldl')
count_pn :: (Num a, Ord a) => [a] -> (Int, Int)
count_pn = foldl' f (0, 0)
where f (np, nn) x
| … = …
| otherwise = …
Here you need to still implement the f function. Here (np, nn) is the 2-tuple with the amount of positive and negative items counted so far, and x the element we want to count next.

Haskell map function, return a list without zeroes

Here is my code:
x = map classify[1..20]
classify :: Int -> Int
classify n
| n `mod` 2 == 0 = n + 2
| otherwise = 0
When calling x it returns a list
[0,4,0,6,0,8,0,10,0,12,0,14,0,16,0,18,0,20,0,22]
How can I specify that I want just numbers that are not 0 is list:
[4,6,8,10,12,14,16,18,20,22]
You can use a filter :: (a -> Bool) -> [a] -> [a] for this. This function takes a function (of type a -> Bool called the "predicate") and a list, and it generates a list of values where the predicate is satisfied (returns True for that element).
So you can filter out zeros with:
filter (0 /=) mylist
For your sample list, this generates:
Prelude> filter (0 /=) [0,4,0,6,0,8,0,10,0,12,0,14,0,16,0,18,0,20,0,22]
[4,6,8,10,12,14,16,18,20,22]
That being said, for this specific case, you can save yourself the trouble from generating such elements in the first place by making "hops of 2":
x = map classify [2, 4..20]
This thus will map a list that contains [2,4,6,8,10,12,14,16,18,20], all the elements in between will - given your function - be mapped to zero. By making hops of two, we avoid calculating these values in the first place. But this of course only works for this specific case.

Haskell - Could not deduce (Num Bool) arising from the literal `0'

My program is suposed to sum the number of students with a grade above 9 (from 0 to 20), from an input like this:
aprov [("John",14)("Martha",8)("Elsa",12)]
The output should be "2". But while compiling it:
k = 0
aprov [] = 0
aprov ((a,n):y) = if n > 9 then k == k + 1 else k == k
GHCi gives me this error:
Could not deduce (Num Bool) arising from the literal `0'
from the context (Num a, Ord a)
bound by the inferred type of
aprov :: (Num a, Ord a) => [(t, a)] -> Bool
at prog.hs:(29,1)-(30,55)
Possible fix: add an instance declaration for (Num Bool)
In the expression: 0
In an equation for `aprov': aprov [] = 0
What can I do to fix it. And by the way is how can I limitate the "n" so that the maximium is 20?
Thank you for the help!
The problem is that you specify
aprov [] = 0
And then on the next line you say
aprov ((a,n):y) = if n > 9 then k == k + 1 else k == k
Which returns one of the two expressions
k == k + 1
Or
k == k
Which are booleans. So the compiler thinks that your function has to return a Bool, but you also have it return 0, which is a Num a => a, and Bool is not a Num.
You say that you want to count the students whose grade passes a particular test, in this case (>9). Well, in Haskell all values are immutable, you can't change them from their initial values. This is hard at first, we're used to being able to modify variables, but in Haskell there are no variables.
Instead, we can use functions to perform the operations we would normally use variables for. So let's list the problem statement and the steps we can take to get there:
Count the number of students with a grade above 9
We can solve this with the steps:
Find the students with a grade above 9
Count the number of those students.
Let's solve the first step:
-- A simple type alias to make our type signatures more readable
-- This just says that "Student" and "(String, Int)" are interchangeable
type Student = (String, Int)
withMinGrade :: Int -> [Student] -> [Student]
withMinGrade minGrade [] = []
withMinGrade minGrade ((name, grade):rest) =
if grade > minGrade
then (name, grade) : withMinGrade minGrade rest
else withMinGrade minGrade rest
So here we say that if we ask for which students have a minimum grade from an empty list, we get an empty list back. If there's at least one student in the list, we check their grade against the minimum allowed, and if it's greater than we return it along with the performing the same operation on the rest of the students, otherwise we just check the rest of the students. If this seems like a lot of work, it's because it is! Haskell comes with a handy function built-in for performing this exact operation called filter. It looks like
filter :: (a -> Bool) -> [a] -> [a]
filter condition [] = []
filter condition (x:xs) =
if condition x -- Apply the function "condition" to "x" returning a Bool
then x : filter condition xs
else filter condition xs
Notice how this is basically the same as withMinGrade, but generalized to any condition. Using filter, we can implement withMinGrade much more simply:
withMinGrade :: Int -> [Student] -> [Student]
withMinGrade minGrade students = filter checkStudent students
where checkStudent (name, grade) = grade > minGrade
We could also do this with a lambda function inline so we don't have to define checkStudent:
withMinGrade minGrade students = filter (\(name, grade) -> grade > minGrade) students
Or even with some fun function composition:
withMinGrade minGrade students = filter ((> minGrade) . snd) students
I'll let you play with this definition to figure out how it works
Now to solve problem 2. This one uses a similar style of recursion, but we return a number instead of a list:
-- count should work on any kind of list
count :: [a] -> Int
count [] = 0
So that case is easy, an empty list has 0 elements in it. What about a list that has at least one element? Well, intuitively, we'd want it to return a count 1 greater than the length of the rest of the list, or with code
count :: [a] -> Int
count [] = 0
count (x:xs) = 1 + count xs
So very simply, we say that the number of elements in a list is just 1 more than the number of elements in the tail of the list. Again, Haskell has a built in function for this (that's more efficient) called length that we can use instead! It's a drop in replacement for count.
So wrapping up, we can combine these two functions, withMinGrade and length, to write our desired function, but I'll leave that step as homework. Since this is your first Haskell program, I'll also direct you towards Learn You a Haskell, the very easy-to-read book I used to get started with this fun and powerful language. It'll show you many examples and give lots of explanations of how Haskell works, and how you can do general programming without ever needing to modify a variable again! It's difficult to "get" at first, but once you embrace immutability, you'll wish you had it in C/C++/Python/Java/.NET/Ruby/Bash/Javascript/etc. It really makes it easier to understand how code works and be sure that it will always work that way every single time.

Convert Int into [Int]

I'm looking through a past exam paper and don't understand how to convert Int to [Int].
For example, one of the questions asks us to produce a list of all the factors of a whole number excluding both the number itself and 1.
strictFactors Int -> [Int]
strictFactors x = ???
I'm not asking for anyone to do this question for me! I just want to know how I'd convert an integer input to a list of integer output. Thanks!
Perhaps it would be easiest to have a look at some similar code. As requested, I won't give you the answer, but you should be able to use these ideas to do what you want.
Brute force
Here we're just going to use all the pairs of numbers between 1 and x to test if we can make x as the sum of two square numbers:
sumOfSquares :: Int -> [Int]
sumOfSquares x = [ (a,b) | a <- [1..x], b <- [a..x], a^2 + b^2 == x]
You call this like this:
ghci> asSumOfSquares 50
[(1,7),(5,5)]
because 50 = 1^2+7^2 and also 50 = 5^2 + 5^2.
You can think of sumOfSquares as working by first taking an a from the list [1..x] of numbers between 1 and x and then another between that and x. It then checks a^2 + b^2 == x. If that's True, it adds (a,b) to the resulting list.
Generate and check
This time let's generate some single numbers then check whether they're a multiple of another. This will calculate the least common multiple (lcm). For example, the least common multiple of 15 and 12 is 60, because it's the first number that's in both the 15 and 12 times tables.
This function isn't of the type you want but it uses all the techniques you want.
lcm :: Int -> Int -> Int
lcm x y = head [x*a | a <- [1..], (x*a) `mod` y == 0]
You can call that like this:
ghci> lcm 12 15
60
This time the list of numbers [1..] is (in principle) infinite; good job we're just picking the first one with head!
(x*a) `mod` y == 0 does the checking to see whether the number x*a is a multiple of y (mod gives the remainder after division). That's a key idea you should use.
Summary
Use a <- [1..end] to generate numbers, test them with a True/False expression (i.e. a Bool), perhaps using the mod function.
I'm quite new at Haskell but can think of a myriad ways of "converting" an Int to a list containing that same Int:
import Control.Applicative (pure)
sane_lst :: Int -> [Int]
sane_lst x = [x]
lst :: Int -> [Int]
lst x = take 1 $ repeat x
lst' :: Int -> [Int]
lst' = replicate 1
lst'' :: Int -> [Int]
lst'' = return
lst''' :: Int -> [Int]
lst''' = pure
lst'''' :: Int -> [Int]
lst'''' x = enumFromTo x x
I guess the point here is that you don't "convert" to a list, you rather "construct" the list you need. The staightforward strategy for the kind of question you posed is to find something that will give you a suitable starting list to work with based on your parameter, then filter, fold or comprehend as needed.
For example when I say:
lst x = take 1 $ repeat x
I'm first constructing an infinite list repeating the value I passed in, and then taking from it a list containing just the first element. So if you think about what kind of list you need to start with to find the solution to your problem you'll be halfway there.
If your only goal is to convert between the types (for now) then strictFactors x = [x] is the most canonical answer. This function is also called pure since [] is what's known as an Applicative and return since [] is known as a Monad.

Haskell: Polymorphic functions explanation

So i am given this
intCMP :: Int -> Int -> Ordering
intCMP a b | a == b = EQ
| a < b = LT
| otherwise = GT
intCMPRev :: Int -> Int -> Ordering
intCMPRev a b | a == b = EQ
| a < b = GT
| otherwise = LT
floatCMP :: Float -> Float -> Ordering
floatCMP a b | a == b = EQ
| a < b = LT
| otherwise = GT
I need to write this function
sort3 :: Ord a => (a -> a-> Ordering) -> [a] -> [a]
sort3 cmp xs =
Which will sort 3 or less elements by comparison. No recursion. I was wondering how this works as far as passing say intCMP. Why would you pass that into the sort function? Does it serve a purpose when sorting and returning the sorted list? I'm not really sure how to do the comparisons manually like that without any sort of recursive call, so I'm just trying to understand it better.
I was thinking of doing 3 comparisons and then moving the element to a certain position in the list, but i really don't know how i could even do this in haskell. Any clues on how to start this would be great. Maybe some sort of pattern?
Thanks.
Partial answer to the first part of your question:
Passing in intCMP to sort3 lets you control the way the sorting is done. Presumably, sort3 intCMP [7,3,6] will return [3,6,7], whereas sort3 intCMPRev [7,3,6] will return [7,6,3]. You could even make your own weird sorting functions like first all the even numbers and then all the odd ones in descending order, like so:
intCMPWeird :: Int -> Int -> Ordering
intCMPWeird a b
| even a && even b = intCMP a b -- even numbers compare as usual
| odd a && odd b = intCMPRev a b -- odd numbers compare in reverse order
| even a && odd b = LT -- evens are all 'smaller' than odds
| odd a && even b = GT -- odds are all 'greater' than evens
Using this, sort3 intCMPWeird [7,3,6] should give [6,7,3].
What happens during typechecking when you pass one of the intCMP... functions into sort3 is (in a very small nutshell) that the compiler tries to match the type of sort3's first argument (a -> a -> Ordering) with the type of the supplied value (Int -> Int -> Ordering) and succeeds in doing that, by making a equal to Int. Then it needs to check whether the constraint Ord a is satisfied for Int, which works! Finally the compiler can figure out that the type of sort3 intCMP is [Int] -> [Int]. Similarly, sort3 floatCMP has type [Float] -> [Float].
I'm not 100% sure why the Ord constraint is on the type of sort3, since you can get the needed information from the passed-in comparison function - are you sure you've typed that correctly?
EDIT: Hint on how to use a where clause to get a readable definition, you still have to fill in some bits and add some more clauses:
sort3 cmp [x,y,z]
| x <= y && somethingElse1 = listWithXyzInSomeOrder1
| x <= z && somethingElse2 = listWithXyzInSomeOrder2
where a <= b = cmp a b /= GT
Here's a hint:
If you have an empty list, clearly the result of sorting it will be an empty list.
Likewise, a list with just a single element is also already sorted.
If you have a 2-element list, there are only 2 possible orderings, hence only 2 possible return values from your function.
If you have a 3-element list, there are 6 possible orderings (the first element can be 1 of 3 input elements, the next element can be 1 of the 2 remaining, leaving only 1 choice for the last element). You can easily write down the 6 different conditions, causing you to return 1 of the 6 possible lists of the 3 elements.
You're not writing polymorphic functions (which is by definition a function that takes more than one type). Write one first:
cmp :: Ord a => a -> a -> Ordering
cmp x y =
| x == y = EQ
| x < y = LT
| otherwise = GT
You would write the above that way the functionality that compares the elements in the sort, need not be a part of the sort. To sort a list is by nature recursive: at least if length is undefined. To achieve this simply write a sort that can make use of your custom comparison, here is quick sort though you could write a different type of sort.
sort3 :: (Ord a) => [a] -> [a]
sort3 [] = []
sort3 (x:xs) =
let smallerSorted = filter (<=)
biggerSorted = filter(>)
in smallerSorted ++ [x] ++ biggerSorted

Resources