I want to write a function wp (without primes) which removes all the primes from a list
of numbers. Thus, wp [1, 2, 3, 4, 5, 6, 7] = [1, 4, 6].
I tried coding it like this:
wp :: [Int] -> [Int]
prime :: Int -> Bool
prime n = if f n > 0 then False else True
where f n = foldl (\acc x -> if n `mod` x == 0 then acc = acc + 1 else acc = acc + 0) 0 [2..n-1]
wp xs = filter (not.prime) xs
But when compiling it, I get the "parse error on input =" error but I can't find my syntax error. Any ideas?
Your problem is in the use of acc = acc + x. You just need to write it as acc + 1 or acc + 0 (or just acc really) instead. Also, I would recommend writing the function signature on top of the function definition, rather than a C-style list at the top.
Finally, I should note that wp will not include 1 in the result, so you will have to manually include it.
prime :: Int -> Bool
prime n = if f n > 0 then False else True
where f n = foldl (\acc x -> if n `mod` x == 0 then acc + 1 else acc) 0 [2..n-1]
wp :: [Int] -> [Int]
wp xs = 1 : filter (not.prime) xs
Related
I think about the function to count all positives numbers in a list. My idee was
countPositives :: [Int] -> Int
countPositives xs = length [ x | x <- xs, x > 0]
That code work, but I thinking it is possible to write with the filter function or with guards. Is it possilbe and if yes, how can I write it?
Both approaches would be pretty straightforward.
Filter the collection and count it's length:
countPositives' :: [Int] -> Int
countPositives' = length.filter (>0)
With guards:
countPositives'' :: [Int] -> Int
countPositives'' [] = 0
countPositives'' (x:xs) | x > 0 = 1 + countPositives'' xs
| otherwise = countPositives'' xs
As yet another alternative, use a fold:
ghci> lst = [1, 2, 4, 7, -2, -3, 0, 8]
ghci> foldr (\x i -> if x > 0 then i + 1 else i) 0 lst
5
Given two lists of digits such as [1, 2, 0] = 120 and [1,0,1] = 101, my function sub should return the list [1, 9] = 19 but the function is returning [2, -1] instead. How do I solve this carry problem? It works fine when there isn't a carry and it only receives positive numbers.
Here's the code I have:
sub_Carry :: Integer -> [Integer] -> [Integer] -> [Integer]
sub_Carry c x []
| c == 0 = x
| otherwise = sub_Carry 0 [c] x
sub_Carry c [] x
| c == 0 = x
| otherwise = sub_Carry 0 x [c]
sub_Carry c (x : xs) (y : ys) = (x - y) : sub_Carry c xs ys
sub :: [Integer] -> [Integer] -> [Integer]
sub op1 op2
| to_Integer(op1) == to_Integer(op2) = [0]
| to_Integer(op1) > to_Integer(op2) = drop_Zeros (reverse (sub_Carry 0 (reverse op1) (reverse op2)))
| otherwise = [-1] ++ drop_Zeros (reverse (sub_Carry 0 (reverse op1) (reverse op2)))
Other considerations:
I've have other utility functions such as to_Integer that converts the list into it's correspondent integer, drop_Zeros that removes zeros to the right of the list ([0, 1, 0] = [1, 0])
in the case the result is a negative number it should return the list with -1 at the head ([1, 0, 0] - [1, 0, 1] = [-1, 1])
I noticed that you don't use the parameter c for carrying. It is the central point of the exercise. It is also necessary to solve the case when the list of a parameter y ends earlier than x. My program works only for positive results. So I also modified the function sub to reverse parameters when op1 < op2. Now there should be always a positive result, which you then negate using the constant -1.
sub_Carry :: Integer -> [Integer] -> [Integer] -> [Integer]
sub_Carry 0 [] [] = []
sub_Carry c x [] = sub_Carry c x [0]
sub_Carry c (x : xs) (y : ys)
| (x - y - c) < 0 = (10 + x - y - c) : sub_Carry 1 xs ys
| otherwise = (x - y - c ) : sub_Carry 0 xs ys
sub :: [Integer] -> [Integer] -> [Integer]
sub op1 op2
| to_Integer(op1) == to_Integer(op2) = [0]
| to_Integer(op1) > to_Integer(op2) = drop_Zeros (reverse (sub_Carry 0 (reverse op1) (reverse op2)))
| otherwise = [-1] ++ drop_Zeros (reverse (sub_Carry 0 (reverse op2) (reverse op1)))
I would like to count the number of positive integers/elements in the list. This returns the elements with positive values, how can I count the elements? would like to construct something like count(array(...)).
I would like to see a version with i++ and foldl. That would be very helpful.
countPositivesRec :: [Int] -> [Int]
countPositivesRec [] = []
countPositivesRec (x:xs) | x >= 0 = x : tl
| otherwise = tl
where tl = countPositivesRec xs
Here's a hint: follow the same recursion scheme as before, but return an int at every step.
countPositivesRec :: [Int] -> Int
---
countPositivesRec [] = 0 -- no positives in the empty list
countPositivesRec (x:xs) | x >= 0 = ??
| otherwise = ??
where tl = countPositivesRec xs
One you solve this, it can be rewritten using foldr, if you want.
If you really want to use foldl instead, I would suggest you start by defining a function f such that
f (f (f 0 x0) x1) x2
evaluates to the number of positives in x0,x1,x2. Then you can use foldl f 0 inputList
The function you've written is filter (>=0). As Paul pointed out, the only step remaining is to count and length does that. We can transform the function step by step:
countPositivesRec :: [Int] -> [Int]
countPositivesRec [] = []
countPositivesRec (x:xs) | x >= 0 = x : tl
| otherwise = tl
where tl = countPositivesRec xs
Observe that xs is only used in the transformed form tl. That's what makes this a right fold.
onlypos1 = foldr maybekeep []
where maybekeep x tl | x >= 0 = x : tl
| otherwise = tl
This operation is known as a filter, keeping only some parts:
onlypos2 = filter dowekeep
where dowekeep x = x >= 0
onlypos3 = filter (\x -> x >= 0)
onlypos4 = filter (>= 0)
But this is of course only one of many possible approaches. For instance, strictness analysis can lead to the conclusion that length is better implemented as foldl' (\a _ -> succ a) 0 than foldr (\_ a -> succ a) 0. Indeed, that is its basic form in the Prelude:
length = foldl' (\c _ -> c+1) 0
We see that the combining function of length ignores the value of one argument, merely requires it to be there. This can naturally be merged with our condition that only some elements count:
lengthFilter1 = length . filter
lengthFilter2 pred = foldl' predCount 0
where predCount c x = if pred x then c+1 else c
countNonNegative = lengthFilter2 nonNegative
where nonNegative x = x >= 0
Incidentally, 0 isn't positive. It's non-negative.
In the end, Haskell's lazy lists mean we can use them to fuse traversals; length . filter (>=0) will only read the input list once, because the only reason it's processing results from filter is that length consumes them. The filtered list never exists as a fully expanded structure, unlike e.g. Python or PHP. This form is likely one of the most readable, but others exist, e.g.:
countNonNegatives xs = sum [1 | x <- xs, x >= 0]
You have
filtering p cons x r = if | p x -> cons x r | otherwise -> r
countPositives = length
. filter (> 0)
= foldr (\x r -> r + 1) 0 -- r++
. foldr (filtering (> 0) (:) ) []
= foldr (filtering (> 0) (\x r -> r + 1)) 0
(since folds fuse by composing their reducer transformers, a-la "fold replaces the cons with a reducer operation, so why create the cons in the first place if it gonna be replaced anyway"), and
filtering (> 0) (\x r -> r + 1) x r
= if | (> 0) x -> (\x r -> r + 1) x r | otherwise -> r
= if | x > 0 -> r + 1 | otherwise -> r
and thus, a version with fold and increment that you wanted,
countPositives = foldr (\x r -> if | x > 0 -> r + 1 | otherwise -> r) 0 -- r++
You can take it from here.
The goal is to validate a list of numbers (credit card number for example ) to first initiate it, reverse it, and then double it, and that would give the sum. Then it would tell if it is valid or in-valid. I have written the code but it wont compile right. It keeps saying this: test.hs:22:1: Parse error in pattern: sumNum.
Here is my code:
main = do
toDigits :: Integer -> [Integer]
toDigitsRev :: Integer -> [Integer]
toDigitsRev n
where
n <= 0 = []
otherwise = n `mod` 10 : toDigitsRev (n `div` 10)
toDigits = reverse . toDigitsRev
double :: [Integer] -> [Integer]
double [] = []
double (x:[]) = [x]
double (x:y:zs) = x : (2 * y) : double zs
doubleRev = reverse . double . reverse
sumNum :: [Integer] -> Integer
sumNum [] = 0
sumNum (x:xs)
x < 10 = x + sumNum xs
otherwise = (x `mod` 10) + (x `div` 10) + sum xs
validate :: Integer -> Bool
validate n = (mod (sumNum (doubleRev (toDigits n))) 10) == 0
You forgot the guard bars:
sumNum (x:xs)
| x < 10 = ...
| otherwise = ...
Without the pipe characters, the compiler sees it as sumNum (x:xs) x < 10 = x + sumNum xs, which doesn't make sense as a pattern, since it seems to suggest you have 3 more arguments, namely x, < and 10, although < does not make sense as a name by itself. Alternatively you could just skip the guard altogether, since
> map (`mod` 10) [0..9] == [0..9]
True
> map (`div` 10) [0..9] == replicate 10 0
True
So all you save is a little efficiency. Since you're working with very small inputs you don't really need to worry about this, so you could just use sumNum [] = 0; sumNum (x:xs) = (x `mod` 10) + (x `div` 10) + sum xs, or more simply sumNum = sum . map (\x -> (x `mod` 10) + (x `div` 10)).
I have written a function to compute the median value of a list
task3 xs | null xs = Nothing
| odd len = xs !! mid
| even len = evenMedian
where len = length xs
mid = len `div` 2
evenMedian = (xs !! mid + xs !! (mid+1)) / 2
I thought it is right and it also pass the load. But when I use the function, it did not work.
What is wrong here?
As Lee mentioned, the list must be sorted first.
(The median of [1,1,8,1,1] is 1 (not 8). so you have to sort it to [1,1,1,1,8] and then take the one in the middle).
The other thing is, that you return Nothing, so the other results have to be of type Maybe a too:
Just $ xs !! mid
Just evenMedian
You can use sort from Data.List to sort your list before applying it to task3.
Like so:
task xs = task3 (sort xs)
How about Median of Medians? Note that this computes only an approximation to the median.
Here is a Haskell implementation:
import Data.List
median :: Ord a => [a] -> a
median xs = select (length xs `div` 2) xs
select :: Ord a => Int -> [a] -> a
select i xs
| n <= 5
= sort xs !! i
| lengthLower == i
= medianOfMedians
| lengthLower < i
= select (i - lengthLower - 1) upperPartition
| otherwise
= select i lowerPartition
where
n = length xs
medianOfMedians = median (map median (chunksOf 5 xs))
(lowerPartition, _:upperPartition) = partition (< medianOfMedians) xs
lengthLower = length lowerPartition
chunksOf :: Int -> [a] -> [[a]]
chunksOf _ [] = []
chunksOf n xs
| (beginning, rest) <- splitAt n xs
= beginning : chunksOf n rest
Recursion could do the job also.
import Data.List
medianFromSorted :: Fractional a => [a] -> Maybe a
medianFromSorted [] = Nothing
medianFromSorted [a] = Just a
medianFromSorted [a,b] = Just ((a + b) / 2)
medianFromSorted (a:xs) = medianFromSorted (init xs) -- init is not efficient
median :: Ord a => Fractional a => [a] -> Maybe a
median = medianFromSorted . sort
My version of median for Integer
import Data.List (sort)
getMiddle [] = 0
getMiddle xs = (a' + b') `div` 2
where a' = head $ drop a xs
b' = head $ drop b xs
a = (n `div` 2)
b = n' - 1
n' = n `div` 2
n = length xs
median :: [Integer] -> Integer
median [] = 0
median xs = result
where result = if (n `mod` 2 == 0)
then getMiddle sorted
else head $ drop a sorted
a = (n - 1) `div` 2
n = length xs
sorted = sort xs
main = print $ median [1, 4, 5, 7, 9, 100]
-- 6
Even with kaan's answer, this code will still not produce a correct median. Another issue that has been overlooked is that Haskell lists are zero indexed. As a result, all of the code is correct with kaan's additions except
evenMedian = (xs !! mid + xs !! (mid+1)) / 2
which should actually be
evenMedian = (xs !! (mid - 1) + xs !! mid) / 2
Otherwise the result is incorrect. The wrong way produces task3 [1, 2, 3, 4] == Just 3.5, while the correct way produces task3 [1, 2, 3, 4] == Just 2.5