Reputation: 65
I have this code for sorting list of even number of items:
sort [] = []
sort l = sortN l (length l)
sortN l 0 = l
sortN l n = sortN (swap l) (n - 1)
swap [] = []
swap (a:b:t) | a <= b = a : b : (swap t)
swap (a:b:t) | b < a = b : a : (swap t)
and I am stuck. For some reason, which I don't understand it returns results as if only one swap was always called.
Also, please do not post here better and more efficient ways how to sort. I am aware of them. I want to know why this is wrong, not other solutions.
Thank you.
Upvotes: 0
Views: 157
Reputation: 52280
Let me offer you a working version (there was the one-element case missing from swap
so as far as I see you will run into trouble else:
swap [] = []
swap [a] = [a]
swap (a:b:t)
| a <= b = a : swap (b:t)
| otherwise = b : swap (a:t)
I will not be tempted into giving you a different algorithm but still you don't need to run swap xs
length xs
times - you just have to run it till the output is not changing anymore:
sort :: Ord a => [a] -> [a]
sort = fix swap
swap :: Ord a => [a] -> [a]
swap [] = []
swap [a] = [a]
swap (a:b:t)
| a <= b = a : swap (b:t)
| otherwise = b : swap (a:t)
fix :: Eq a => (a -> a) -> a -> a
fix f x = let x' = f x
in if x' /= x then fix f x' else x
fix
here will do exactly that - it applies f
to x
till the result is not changing anymore.
for example:
sort [3,6,1,3,2]
will call swap
only 4 timessort [1..10]
it will be called only oncemaybe you are interested in how you can easily check your implementations - here is a QuickCheck test (I used to verify my solution too) that does this:
import Test.QuickCheck
isSorted :: Ord a => [a] -> Bool
isSorted [] = True
isSorted [_] = True
isSorted (a:b:t) = a<=b && isSorted (b:t)
checkSortAlg :: ([Int] -> [Int]) -> IO ()
checkSortAlg sortAlg = quickCheck test
where
test xs = isSorted $ sortAlg xs
you just have to run it like this (for example in ghci):
checkSortAlg sort
it should print +++ OK, passed 100 tests.
here is what it does for for the version with the missing swap [a] = [a]
case:
(after 3 tests and 1 shrink):
Exception:
SimpleSort.hs:(9,1)-(12,30): Non-exhaustive patterns in function swap
[0]
this tells you that after 3 tests it used some list that after shrinking to [0]
still threw the Non-exhaustive patterns
exception - so it basically tells you to look for the single element case here ;) - of course the compiler should have too
Upvotes: 1
Reputation: 64740
The problem is you are only considering the same pairs of element on each pass. Consider:
swap (a:b:t) | a <= b = a : b : (swap t)
swap (a:b:t) | b < a = b : a : (swap t)
What if we have a list [4,1,1,1]
?
swap [4,1,1,1] = 1 : 4 : swap [1,1] = 1:4:1:1:[]
Ok, now lets look at the next iteration of sortN
and its call to swap
:
swap [1,4,1,1] = 1 : 4 : swap [1,1]
So you see, swap
implicitly assumes every pair of elements is ordered within the list. Instead consider the implementation a: swap (b:t)
and b : swap (a : t)
.
Upvotes: 6