Drop nth Element from list - haskell

I have been teaching myself Haskell for a month or so and today I was reading the solution of 16th problem and came up with a question.
Here is a link : http://www.haskell.org/haskellwiki/99_questions/Solutions/16
Basically, this question asks to make a function that drops every N'th element from a list.
For example,
*Main> dropEvery "abcdefghik" 3
"abdeghk"
The first solution in the link is
dropEvery :: [a] -> Int -> [a]
dropEvery [] _ = []
dropEvery (x:xs) n = dropEvery' (x:xs) n 1
where
dropEvery' (x:xs) n i = (if (n `divides` i) then [] else [x])++ (dropEvery' xs n (i+1))
dropEvery' [] _ _ = []
divides x y = y `mod` x == 0
My question is why dropEvery defines the case of empty lists while dropEvery' can take care of empty list?
I think dropEvery [] _ = [] can be simply eliminated and modifying a bit of other sentences as following should work exactly the same as above and looks shorter.
dropEvery :: [a] -> Int -> [a]
dropEvery xs n = dropEvery' xs n 1
where
dropEvery' (x:xs) n i = (if (n `divides` i) then [] else [x])++ (dropEvery' xs n (i+1))
dropEvery' [] _ _ = []
divides x y = y `mod` x == 0
Can anyone help me figure out about this?

I think they are the same and the author could have simplified the code as you suggested. For the heck of it I tried both versions with QuickCheck and they seem to be the same.
import Test.QuickCheck
dropEvery :: [a] -> Int -> [a]
dropEvery [] _ = []
dropEvery (x:xs) n = dropEvery' (x:xs) n 1
where
dropEvery' (x:xs) n i = (if (n `divides` i) then [] else [x])++ (dropEvery' xs n (i+1))
dropEvery' [] _ _ = []
divides x y = y `mod` x == 0
dropEvery2 :: [a] -> Int -> [a]
dropEvery2 xs n = dropEvery' xs n 1
where
dropEvery' (x:xs) n i = (if (n `divides` i) then [] else [x])++ (dropEvery' xs n (i+1))
dropEvery' [] _ _ = []
divides x y = y `mod` x == 0
theyAreSame xs n = (dropEvery xs n) == (dropEvery2 xs n)
propTheyAreSame xs n = n > 0 ==> theyAreSame xs n
And in ghci you can do
*Main> quickCheck propTheyAreSame
+++ OK, passed 100 tests.
I also tested a few corner cases by hand
*Main> dropEvery [] 0
[]
*Main> dropEvery2 [] 0
[]
*Main> dropEvery [] undefined
[]
*Main> dropEvery2 [] undefined
[]
So them seem to the same.
So our learning outcomes:
Quickcheck is perfect for this kind of stuff
Don't underestimate yourself. :)

Related

Haskell: Change the (n,m)th element in a Lists in List

The replaceAtMatrix function should take in a tuple (Int,Int) that decides what position is the value that needs to be changed, a value to be changed to, and the List in List [[a]].
If the tuple's values exceed the lists length the original [[a]] needs to be returned.
replaceAtList :: Int -> a -> [a] -> [a]
replaceAtList _ _ [] = []
replaceAtList 0 a (_:xs) = a:xs
replaceAtList number a (x:xs)
| number < 0 = x:xs
| number > (length (x:xs)-1) = x:xs
| otherwise = x : replaceAtList (number-1) a xs
replaceAtMatrix :: (Int,Int) -> a -> [[a]] -> [[a]]
replaceAtMatrix _ _ [] = []
replaceAtMatrix (0,num2) a (x:xs) = replaceAtList num2 a x : xs
replaceAtMatrix (num1,num2) a (x:xs)
| num1 < 0 = x:xs
| num1 > (length (x:xs)-1) = x:xs
| num2 < 0 = x:xs
| num2 > (length (x:xs)-1) = x:xs
| otherwise = x : replaceAtMatrix (num1-1,num2) a xs
There are test for which I checked, and it passes most of them, but there's one where it goes in an infinite cycle. Here's the tests that work.
replaceAtMatrix (-1,0) 'A' ["bcd","lds","rtz"] == ["bcd","lds","rtz"]
replaceAtMatrix (0,0) 'A' ["bcd","lds","rtz"] == ["Acd","lds","rtz"]
replaceAtMatrix (2,0) 'A' ["bcd","lds","rtz"] == ["bcd","lds","Atz"]
replaceAtMatrix (3,0) 'A' ["bcd","lds","rtz"] == ["bcd","lds","rtz"]
replaceAtMatrix (2,2) 'A' ["bcd","lds","rtz"] == ["bcd","lds","rtA"]
And here's the one that doesn't.
Edit: I just realized it's probaly beacuse I use length on an infinite list. How can I rewrite it without using length?
take 5 (replaceAtMatrix (1,2) 100 [[1..],[1,11..],[],[12,13,14]] !! 1) == [1,11,100,31,41]
Without the guard, I get a variable not in scope error.
replaceAtList :: Int -> a -> [a] -> [a]
replaceAtList _ _ [] = []
replaceAtList 0 a (_:xs) = a:xs
replaceAtList number a (x:xs) = x : replaceAtList (number-1) a xs
replaceAtMatrix :: (Int,Int) -> a -> [[a]] -> [[a]]
replaceAtMatrix _ _ [] = []
replaceAtMatrix (0,num2) a (x:xs) = replaceAtList num2 a x : xs
replaceAtMatrix (num1,num2) a (x:xs) = x : replaceAtMatrix (num1-1,num2) a xs
I think you have your answer, and can make progress, but I thought it might be interesting to show you an alternate implementation. There's some repetition in your existing code of traversing a list to a specific spot, and then making a change. Here's an idea for how you might implement that just once:
onIndex :: Int -> (a -> a) -> ([a] -> [a])
onIndex n f = if n < 0 then id else loop n where
loop _ [] = []
loop 0 (x:xs) = f x:xs
loop n (x:xs) = x:loop (n-1) xs
Rather than taking an element and replacing that element, this takes an arbitrary editing function and applies that function to the element at the appropriate position. We can use this to replace an element with value foo using const foo as the editing function. But, and this is the key thing, we can also use an editing function that itself calls onIndex!
replaceAtMatrix :: (Int, Int) -> a -> [[a]] -> [[a]]
replaceAtMatrix (m, n) = onIndex m . onIndex n . const
Don't use length. This will error on infinite lists: you do not need this: in case the number > length somelist, eventually it will reach the end of the list:
replaceAtList :: Int -> a -> [a] -> [a]
replaceAtList _ _ [] = []
replaceAtList n _ xs
| n < 0 = xs
replaceAtList 0 a (_:xs) = a:xs
replaceAtList number a (x:xs) = x : replaceAtList (number-1) a xs
replaceAtMatrix :: (Int,Int) -> a -> [[a]] -> [[a]]
replaceAtMatrix _ _ [] = []
replaceAtMatrix (m, _) _ xs
| m < 0 = xs
replaceAtMatrix (0,num2) a (x:xs) = replaceAtList num2 a x : xs
replaceAtMatrix (num1,num2) a (x:xs) = x : replaceAtMatrix (num1-1,num2) a xs

Is there a way to use "<=" for pattern matching in Haskell?

I have the following code, that drops every nth element in a list.
dropEvery :: [a] -> Int -> [a]
dropEvery xs n = f xs n ++ dropEvery (drop n xs) n
where
f ys 0 = []
f ys 1 = []
f [] m = []
f (y:ys) n = y : (f ys (n-1))
I would like to make it a bit shorter and was wondering if there is a way to use "<=" in pattern matching. I tried doing this using a where clause, which did not work, why?
f ys m = []
where
m <= 1 || ys == []
How can I shirk this redundancy? Is there a nice way to use "less or equal" in pattern matching?
EDIT: I tried this using guards
where
f ys m
| m <= 1 || null ys = []
| otherwise = (head ys) : (f (tail ys) (n-1))
You can work with a guard:
dropEvery :: [a] -> Int -> [a]
dropEvery xs n = f xs n ++ dropEvery (drop n xs) n
where
f ys i | i <= 1 = []
f [] _ = []
f (y:ys) n = y : (f ys (n-1))
If the condition in the guard is satisfied, then that clause "fires" and thus in this case will return an empty list [].
You will however get stuck in an infinite loop, since you write f xs n ++ dropEvery (n xs) n but drop 3 [] will return [], and thus it will keep calling dropEvery with an empty list.
You can make use of recursion where we each time decrement n until it reaches 0, and then we make two hops, so:
dropEvery :: Int -> [a] -> [a]
dropEvery n = go (n-1)
where go _ [] = []
go i (x:xs)
| i <= 0 = go (n-1) xs
| otherwise = x : go (i-1) xs
We can also work with splitAt :: [a] -> ([a], [a]) and with a pattern guard:
dropEvery n [] = []
dropEvery n ds
| (_:ys) <- sb = sa ++ dropEvery n ys
| otherwise = sa
where (sa, sb) = splitAt (n-1) ds

How to report an error in Haskell code

I am writing a program that returns every rth element from a list. The list can be any type. I want to report an error when r is zero but my code isn't working (it is working fine when I comment out the error line). Can anyone tell me how to report an error in this situation
rthElem :: Int -> [a] -> [a]
rthElem _ [] = []
rthElem 0 (x:xs) = "Error"
rthElem n (x:xs) = rthElem' n 1 (x:xs) where
rthElem' n i (x:xs) = (if (n `divides` i) then
[x] else
[])
++ (rthElem' n (i+1) xs)
rthElem' _ _ [] = []
divides x y = y `mod` x == 0
You could use Maybe or Either in this case.
This is how Maybe looks. Nothing will be our "error".
rthElem :: Int -> [a] -> Maybe [a]
rthElem _ [] = Just []
rthElem 0 (x:xs) = Nothing
rthElem n (x:xs) = Just (rthElem' n 1 (x:xs)) where
rthElem' n i (x:xs) = (if (n `divides` i) then
[x] else
[])
++ (rthElem' n (i+1) xs)
rthElem' _ _ [] = []
divides x y = y `mod` x == 0
main :: IO ()
main = case (rthElem 0 [1..5]) of
Nothing -> putStrLn "Error"
Just elm -> print elm
Another way is using Either. Either will return Left or Right. Left will be our "error".
rthElem :: Int -> [a] -> Either String [a]
rthElem _ [] = Right []
rthElem 0 (x:xs) = Left "Error"
rthElem n (x:xs) = Right (rthElem' n 1 (x:xs)) where
rthElem' n i (x:xs) = (if (n `divides` i) then
[x] else
[])
++ (rthElem' n (i+1) xs)
rthElem' _ _ [] = []
divides x y = y `mod` x == 0
main :: IO ()
main = case (rthElem 0 [1..5]) of
Left err -> putStrLn err
Right elm -> print elm
The best way is using Either. Read more about error handling here.
If you really want to print an error and show it you could use the error function, error :: String -> a
rthElem 0 (x:xs) = error "Error msg here"
But there is a plenty better ways to do this , and you should figure out which one fits in your case , you can use Maybe, Either even monads , here is an interesting link with examples http://www.randomhacks.net/2007/03/10/haskell-8-ways-to-report-errors/
You could use exceptions but you'd also have to transform your function into an IO action.
rthElem :: Int -> [a] -> IO [a]
rthElem _ [] = return []
rthElem 0 _ = ioError $ userError "Error"
rthElem n l = return $ rthElem' n 1 l where
rthElem' n i (x:xs) = (if (n `divides` i) then
[x] else
[])
++ (rthElem' n (i+1) xs)
rthElem' _ _ [] = []
divides x y = y `mod` x == 0

Simple haskell splitlist

I have the following function which takes a list and returns two sublists split at a given element n. However, I only need to split it in half, with odd length lists having a larger first sublist
splitlist :: [a] -> Int -> ([a],[a])
splitlist [] = ([],[])
splitlist l#(x : xs) n | n > 0 = (x : ys, zs)
| otherwise = (l, [])
where (ys,zs) = splitlist xs (n - 1)
I know I need to change the signature to [a] -> ([a],[a]), but where in the code should I put something like length(xs) so that I don't break recursion?
In a real program you should probably use
splitlist :: [a] -> ([a], [a])
splitlist xs = splitAt ((length xs + 1) `div` 2) xs
(i.e. something along the lines of dreamcrash's answer.)
But if, for learning purposes, you're looking for an explicitly recursive solution, study this:
splitlist :: [a] -> ([a], [a])
splitlist xs = f xs xs where
f (y : ys) (_ : _ : zs) =
let (as, bs) = f ys zs
in (y : as, bs)
f (y : ys) (_ : []) = (y : [], ys)
f ys [] = ([], ys)
You can do it using take and drop:
splitlist :: [a] -> ([a],[a])
splitlist [] = ([],[])
splitlist l = let half = (length(l) +1)`div` 2
in (take half l, drop half l)
or you can take advantage of the function splitAt:
splitlist list = splitAt ((length (list) + 1) `div` 2) list
You can do this by using the take and drop built-in functions. But if you want something that can be done with all self written functions try this:
dropList :: Int -> [Int] -> [Int]
dropList 0 [] = []
dropList 0 (x:xs) = x:xs
dropList y [] = []
dropList y (x:xs) = dropList (y-1) xs
takeList :: Int -> [Int] -> [Int]
takeList 0 [] = []
takeList 0 (x:xs) = []
takeList y [] = []
takeList y (x:xs)
| y <= length (x:xs) = x : takeList (y-1) xs
| otherwise = []
split :: Int -> [Int] -> ([Int],[Int])
split 0 [] = ([],[])
split y [] = ([],[])
split y (x:xs) = (takeList y (x:xs), dropList y (x:xs))
main = do
print (split 4 [1,2,3,4,5,6])

Lambda expression parse error on ")"

My task is to re-implement this function
divn :: Integer -> [Integer] -> [Integer]
divn _ [] = []
divn n (x:xs) | mod x n == 0 = x : divn n xs
| otherwise = divn n xs
using 'foldr'.
What I did:
divn' _ [] = []
divn' n (x:xs) = foldr (\x -> if (mod x n == 0) (x:) ([]++)) [] xs
I thought this would work. Actually it doesn't even compile, but says: "Parse error on input ")".
As I didn't find any errors, I decided to re-write if as if' an now its working...
if' True x _ = x
if' False _ x = x
divn' _ [] = []
divn' n (x:xs) = foldr (\x -> if' (mod x n == 0) (x:) ([]++)) [] xs
Does anyone know where's the error?
Thanks!
if needs a then and an else in Haskell,
(\x -> if (mod x n == 0) (x:) ([]++))
should be
(\x -> if (mod x n == 0) then (x:) else id)
Apart from what Daniel Fischer said, you don't need any separate cases: there's no recursion, the empty list case will be handled by foldr. In your code, the first x is always ignored! Correct is
divn' n xs = foldr (\x -> if x`mod`n == 0 then (x:) else id) [] xs
or, by η-reduction,
divn' n = foldr (\x -> if x`mod`n == 0 then (x:) else id) []
Of course, it would be far more idiomatic to simply do
divn'' n = filter ((==0) . (`mod`n))

Resources