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.
Related
I'm learning list operations in Haskell and now I'm trying out various list operations on Maybe list type. Currently, I have this implementation of sum of elements in list in Haskell
sum :: Num a => [a] -> a
sum [] = 0
sum (a:t) = a + sum t
Now I want to do the same thing but instead of returning the value, I want to return a Maybe type instead. And when the list given is empty it should return Nothing.
I've come up with this
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum (a:t) = fmap (a+) (sum t)
But the result of all non empty list given results in Nothing.
From what I understand, the list given will eventually pattern match with the empty list therefore returning Nothing.
How do I fix this so that it returns the expected value and of Maybe type. I can't figure out how to make it work recursively as the normal sum implementation above, so I guess there should be another way. Would prefer if only Prelude module is imported as I'm still trying to absorb stuff inside the Prelude module.
The problem is that your recursive function always uses the empty list as a base case, so your base case value is always Nothing. You only want to return Nothing if the "root" call takes an empty list. Otherwise, you want to use the singleton list as your base case.
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum [x] = Just x
sum (a:t) = fmap (a+) (sum t)
This way, sum [] will never be reached by a recursive call; any non-empty list will hit the base case sum [x] first.
Another way to organize this is to use your original total function as a helper that sums non-empty lists only, and handle the empty list separately.
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum xs = sum' xs
where sum' [] = Just 0
sum' (a:t) = fmap (a+) (sum' t)
Note that sum' can be called on an empty list, but only if it is originally called on a non-empty list.
As #chi points out, the helper function doesn't need to use Maybe at all; since it only sums non-empty lists, you can skip using fmap and sum the list normally; only the final result needs to be wrapped in Just:
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum xs = Just (sum' xs)
where sum' [] = 0
sum' (a:t) = a + sum' t
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.
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.
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.
I have the following list (it’s a length 2 list, but in my assignment I have a length +n list)
xxs = [(11,22,[(33,33,33),(44,44,44)]),(55,66,[(77,77,77),(88,88,88)])]
I’m trying to “replace” one 3-tuple (p1 or p2 or p3 or p4 from the image bellow) by list index (n) and by sub-list index (p).
The function, at the end, should be like:
fooo newtuple n p = (…)
For example: (replace p3 for (98,98,98):
fooo (98,98,98) 2 1
[(11, 22, [(33,33,33) , (44,44,44)]) , (55, 66, [(98,98,98),(88,88,88)])]
I planned the code like following this steps:
Access the pn that I want to change. I manage to achieve it by:
fob n p = ((aux2 xxs)!!n)!!p
where aux2 [] = []
aux2 ((_,_,c):xs) = c:aux2 xs
“replace” the 3-tuple. I really need some help here. I’m stuck. the best code (in my head it makes some sense) that I’ve done: (remember: please don’t be too bad on my code, I’ve only been studying Haskell only for 5 weeks)
foo n p newtuple = fooAux newtuple fob
where fooAux _ [] = []
fooAux m ((_):ds) = m:ds
fob n p = ((aux2 xxs)!!n)!!p
where aux2 [] = []
aux2 ((_,_,c):xs) = c:aux2 xs
Finally I will put all back together, using splitAt.
Is my approach to the problem correct? I really would appreciate some help on step 2.
I'm a bit new to Haskell too, but lets see if we can't come up with a decent way of doing this.
So, fundamentally what we're trying to do is modify something in a list. Using functional programming I'd like to keep it a bit general, so lets make a function update.
update :: Int -> (a -> a) -> [a] -> [a]
update n f xs = pre ++ (f val) : post
where (pre, val:post) = splitAt n xs
That will now take an index, a function and a list and replace the nth element in the list with the result of the function being applied to it.
In our bigger problem, however, we need to update in a nested context. Luckily our update function takes a function as an argument, so we can call update within that one, too!
type Triple a = (a,a,a)
type Item = (Int, Int, [Triple Int])
fooo :: Triple Int -> Int -> Int -> [Item] -> [Item]
fooo new n p = update (n-1) upFn
where upFn (x,y,ps) = (x,y, update (p-1) objFn ps)
objFn _ = new
All fooo has to do is call update twice (once within the other call) and do a little "housekeeping" work (putting the result in the tuple correctly). The (n-1) and (p-1) were because you seem to be indexing starting at 1, whereas Haskell starts at 0.
Lets just see if that works with our test case:
*Main> fooo (98,98,98) 2 1 [(11,22,[(33,33,33),(44,44,44)]),(55,66,[(77,77,77),(88,88,88)])]
[(11,22,[(33,33,33),(44,44,44)]),(55,66,[(98,98,98),(88,88,88)])]
First, we need a general function to map a certain element of a list, e.g.:
mapN :: (a -> a) -> Int -> [a] -> [a]
mapN f index list = zipWith replace list [1..] where
replace x i | i == index = f x
| otherwise = x
We can use this function twice, for the outer list and the inner lists. There is a little complication as the inner list is part of a tuple, so we need another helper function:
mapTuple3 :: (c -> c) -> (a,b,c) -> (a,b,c)
mapTuple3 f (x,y,z) = (x,y,f z)
Now we have everything we need to apply the replace function to our use case:
fooo :: Int -> Int -> (Int,Int,Int) -> [(Int,Int,[(Int,Int,Int)])]
fooo n p newTuple = mapN (mapTuple3 (mapN (const newTuple) p)) n xxs
Of course in the inner list, we don't need to consider the old value, so we can use const :: a -> (b -> a) to ignore that argument.
So you've tried using some ready-made function, (!!). It could access an item in a list for you, but forgot its place there, so couldn't update. You've got a solution offered, using another ready-made function split, that tears a list into two pieces, and (++) which glues them back into one.
But to get a real feel for it, what I suspect your assignment was aiming at in the first place (it's easy to forget a function name, and it's equally easy to write yourself a new one instead), you could try to write the first one, (!!), yourself. Then you'd see it's real easy to modify it so it's able to update the list too.
To write your function, best think of it as an equivalence equation:
myAt 1 (x:xs) = x
myAt n (x:xs) | n > 1 = ...
when n is zero, we just take away the head element. What do we do when it's not? We try to get nearer towards the zero. You can fill in the blanks.
So here we returned the element found. What if we wanted to replace it? Replace it with what? - this calls another parameter into existence,
myRepl 1 (x:xs) y = (y:xs)
myRepl n (x:xs) y | n > 1 = x : myRepl ...
Now you can complete the rest, I think.
Lastly, Haskell is a lazy language. That means it only calls into existence the elements of a list that are needed, eventually. What if you replace the 7-th element, but only first 3 are later asked for? The code using split will actually demand the 7 elements, so it can return the first 3 when later asked for them.
Now in your case you want to replace in a nested fashion, and the value to replace the old one with is dependent on the old value: newVal = let (a,b,ls)=oldVal in (a,b,myRepl p ls newtuple). So indeed you need to re-write using functions instead of values (so that where y was used before, const y would go):
myUpd 1 (x:xs) f = (f x:xs)
myUpd n ... = ...
and your whole call becomes myUpd n xxs (\(a,b,c)->(a,b,myUpd ... (const ...) )).