What ist the difference between these two (Haskell) - sorting

I was checking some codes then i tried to write one of them but i keep getting a parse '=' error but when i copy paste the code from the source it works fine so what is the difference between this;
quicksort2 :: (Ord a) => [a] -> [a]
quicksort2 [] = []
quicksort2 (x:xs) =
let smallerSorted = quicksort2 [a | a <- xs, a <= x]
biggerSorted = quicksort2 [a | a <- xs, a > x]
in smallerSorted ++ [x] ++ biggerSorted
and this ;
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
let smallerSorted = quicksort [a | a <- xs, a <= x]
biggerSorted = quicksort [a | a <- xs, a > x]
in smallerSorted ++ [x] ++ biggerSorted
quicksort2 gets parse error but quicksort doesn't. So where is the difference?
the error -> .hs:5:26: parse error on input `='

One has tabs mixed in the indentation, while the other uses only spaces. This causes problems because whitespace is very significant in Haskell, and your editor may be configured with a different tab width than Haskell (which always uses 8). So it may look OK in your editor, but to the compiler the indentation is all messed up.
This is how your code looks to Haskell:
quicksort2 :: (Ord a) => [a] -> [a]
quicksort2 [] = []
quicksort2 (x:xs) =
let smallerSorted = quicksort2 [a | a <- xs, a <= x]
biggerSorted = quicksort2 [a | a <- xs, a > x]
in smallerSorted ++ [x] ++ biggerSorted
^^^^^^^^
There are tabs here on the two lines above.
This gives a syntax error because the bindings in the let-expression are not properly aligned.
In general, avoid using tabs for indentation in Haskell. Configure your editor to always use spaces and it'll save you a lot of headaches.

Related

Sorting a list of ('String', int) by its int (Haskell)

I am brand new to Haskell, so I'm still learning a lot of things. I was given a list of name and age, and I need to sort them in both alphabetical order and in increasing order using their age. I managed to sort the list alphabetically, but I'm unsure how to do it using its age values. What can I change in the code below? Thank you for your help.
qsort :: (Ord a) => [a] -> [a]
-- check to see if the list is empty
qsort [] = []
qsort [x] = [x] -- Single element list is always sorted
qsort [x, y] = [(min x y), (max x y)]
-- x is the pivot, left quicksort returns smaller sorted and right quicksort bigger sorted
qsort (x:xs) =
qsort [a | a <- xs, a <= x] ++ [x] ++ qsort [a | a <- xs, a > x]
people=[("Steve",20),("Smith",31),("Kris",19),("Beth",21)]
main = do
print(qsort people) -- sort alphabetically
First, let's simplify your function a bit. Both the [x] and [x, y] cases are redundant: they are completely captured by the (x:xs) case. So let's remove those.
qsort :: (Ord a) => [a] -> [a]
qsort [] = []
qsort (x:xs) =
qsort [a | a <- xs, a <= x] ++ [x] ++ qsort [a | a <- xs, a > x]
Now, currently we assume that the type of our list and the type we're sorting by are the same. We call them both a. Let's instead have two types: a will be the type of our list and b will be the type we want to sort by. Only b has to satisfy Ord, and we'll need a function to convert an a into a b so we can sort our list. This is our desired type
qsort :: (Ord b) => (a -> b) -> [a] -> [a]
Our base case is basically the same, except that we ignore the function argument.
qsort _ [] = []
In our recursive case, we compare by applying the function f :: a -> b and then using <= or >.
qsort f (x:xs) =
qsort f [a | a <- xs, f a <= f x] ++ [x] ++ qsort f [a | a <- xs, f a > f x]
Now we can sort by whatever Ord type we want. We can sort by the first element of a tuple
-- Note: (fst :: (a, b) -> a) is in Prelude
print (qsort fst people)
or the second
-- Note: (snd :: (a, b) -> b) is in Prelude
print (qsort snd people)
both by their natural sorting order.
If we want to sort in the opposite order (descending rather than ascending), we can use Down as our function. If we want to sort by some complex order, we can always use the newtype pattern.

Reverse list order without increasing complexity

I wanted an alternative to filter that would, instead of discarding the false cases, keep them in a separate place. I came up with the below, but unfortunately it reverses the list.
Obviously I could append x to ys or zs instead of cons, but this would dramatically increase complexity.
Is there a way to keep it in order without increasing complexity?
splitBy :: (a -> Bool) -> [a] -> ([a],[a])
splitBy f xs = splitBy' f xs ([],[])
where
splitBy' :: (a -> Bool) -> [a] -> ([a],[a]) -> ([a],[a])
splitBy' _ [] result = result
splitBy' f (x:xs) (ys,zs) = if f x then splitBy' f xs (x:ys,zs)
else splitBy' f xs (ys,x:zs)
As others have said, the function is called partition, and it works something like this
partition :: (a -> Bool) -> [a] -> ([a], [a])
partition f = foldr (\x ~(yes,no) ->
if f x
then (x:yes,no)
else (yes,x:no))
([], [])
except that the real version adds an explicit xs parameter, perhaps to help fusion rules work properly. If that funky lazy pattern match makes you nervous, you can write it like this instead:
partition f = foldr (\x r ->
if f x
then (x:fst r,snd r)
else (fst r,x:snd r))
([], [])
If the foldr seems mysterious to you, you can do it like this:
partition f [] = ([], [])
partition f (x:xs)
| f x = (x:fst r, snd r)
| otherwise = (fst r, x:snd r)
where r = partition f xs

Simplifying selectionsort and mergesort

I have managed to implement insertionsort and quicksort in a couple of lines, but selectionsort and mergesort still give me headaches ;)
selectionsort [] = []
selectionsort (x:xs) =
let (minimum, greater) = extractMinimum x [] xs
in minimum : selectionsort greater
extractMinimum minimumSoFar greater [] = (minimumSoFar, greater)
extractMinimum minimumSoFar greater (x:xs)
| x < minimumSoFar = extractMinimum x (minimumSoFar:greater) xs
| otherwise = extractMinimum minimumSoFar (x:greater) xs
Is something like the extractMinimum function available in the standard library? I tried hoogling for (a -> a -> Bool/Ordering) -> [a] -> (a, [a]) without any luck.
mergesort [ ] = [ ]
mergesort [x] = [x]
mergesort xs =
let (left, right) = splitAt (length xs `div` 2) xs
in merge (mergesort left) (mergesort right)
merge xs [] = xs
merge [] ys = ys
merge xxs#(x:xs) yys#(y:ys)
| x < y = x : merge xs yys
| otherwise = y : merge xxs ys
Again, do I have to write merge myself, or can I reuse existing components? Hoogle gave me no useful results for (a -> a -> Bool/Ordering) -> [a] -> [a] -> [a].
There's nothing in the standard libraries, but at least merge is provided by a package on hackage, although I'm not sure it's worth pulling in a dependency for such a simple function.
However,
merge xxs#(x:xs) yys#(y:ys)
| x < y = x : merge xs yys
| otherwise = y : merge xxs ys
produces a non-stable sort, to get a stable sort, the condition to place x should be x <= y.
For extractMinimum, I haven't found anything either, but I can offer an alternative definition,
extractMinimum :: Ord a => a -> [a] -> (a,[a])
extractMinimum x = foldl' select (x, [])
where
select (mini, greater) y
| y < mini = (y, mini:greater)
| otherwise = (mini, y:greater)
A nice definition of selectionSort would be
import Data.List -- for unfoldr
selectionSort :: Ord a => [a] -> [a]
selectionSort = unfoldr getMin
where
getMin [] = Nothing
getMin (x:xs) = Just $ extractMinimum x xs
My suggestion for selection sort:
import Data.List
selectionsort xs = unfoldr f xs where
f [] = Nothing
f xs = Just $ extractMinimum xs
extractMinimum (x:xs) = foldl' f (x,[]) xs where
f (minimum, greater) x | x < minimum = (x, minimum : greater)
| otherwise = (minimum, x : greater)

Haskell -- sort list with impure function

How can I sort list with IO Compare function?
sortWith :: [String] -> (String -> String -> IO Ordering) -> IO [String]
Sortby expects (a->a->Ordering) and I don't know, how to deal with it. I am too lazy to implement quick sort myself.
I'm afraid there is no simple way. If it was possible to lift
sortBy :: Ord a => (a -> a -> Ordering) -> [a] -> [a]
to
sortByM :: (Ord a, Monad m) => (a -> a -> m Ordering) -> [a] -> m [a]
you could see the order of comparisons in implementation of sortBy, violating referential transparency.
In general, it's easy to go from xxxM to xxx but not conversely.
Possible options:
Implement a monadic sorting method
Use the monadlist library, which contains insertion sort (as in dflemstr's answer)
Use unsafePerformIO as a hack
Switch to sorting by key and use the Schwartzian transform
sortOnM :: (Monad m, Ord k) => (a -> m k) -> [a] -> m [a]
sortOnM f xs = liftM (map fst . sortBy (comparing snd)) $
mapM (\x -> liftM (x,) (f x)) xs
The sortBy function uses merge sort as the algorithm in GHC, but the Haskell 98 Report dictates that insertion sort should be used.
For simplicity, because I don't have a compiler so I cannot test my code, I will implement insertion sort here:
import Data.Foldable (foldrM)
insertByM :: (a -> a -> IO Ordering) -> a -> [a] -> IO [a]
insertByM _ x [] = return [x]
insertByM cmp x ys#(y:ys') = do
p <- cmp x y
case p of
GT -> do
rest <- insertByM cmp x ys'
return $ y : rest
_ -> return $ x : ys
sortByM :: (a -> a -> IO Ordering) -> [a] -> IO [a]
sortByM cmp = foldrM (insertByM cmp) []
As I said, I haven't tested this code, but it could/should work.
Oh, I've done this one before! Merge sort with monadic comparator:
type MComparator m a = a -> a -> m Ordering
sortByM :: (Monad m, Functor m) => MComparator m a -> [a] -> m [a]
sortByM cmp [] = return []
sortByM cmp [x] = return [x]
sortByM cmp xs = do
let (ys, zs) = partition xs
ys' <- sortByM cmp ys
zs' <- sortByM cmp zs
merge ys' zs'
where merge [] bs = return bs
merge as [] = return as
merge (a:as) (b:bs) = do
comparison <- cmp a b
case comparison of
LT -> (a:) <$> merge as (b:bs)
_ -> (b:) <$> merge (a:as) bs
partition xs = splitAt (length xs `quot` 2) xs
From my blog post: http://unknownparallel.wordpress.com/2012/07/03/using-monadic-effects-to-reverse-a-merge-sort/
Was it Larry Wall who said that laziness is one of the 3 great virtues of a programmer?
It seems you want to transform a function of type (a -> a -> b) into a function of type (a -> a -> c b). Let's plug that into Hoogle. Now, if you know that IO is a Monad, you'll see about the 10th match down in liftM2. Check the type of (liftM2 sortBy), is that what you want?

Merge sorted inputs in Haskell?

I'm a newbie to Haskell, and I'm trying to write an elegant function to merge an arbitrary number of sorted lists into a single sorted list... Can anyone provide an elegant and efficient reference implementation?
Thanks!
Something like this should work:
merge2 pred xs [] = xs
merge2 pred [] ys = ys
merge2 pred (x:xs) (y:ys) =
case pred x y of
True -> x: merge2 pred xs (y:ys)
False -> y: merge2 pred (x:xs) ys
merge pred [] = []
merge pred (x:[]) = x
merge pred (x:xs) = merge2 pred x (merge pred xs)
Here, the function merge2 merges 2 lists. The function merge merges a list of lists. The pred is predicate you use for sorting.
Example:
merge (<) [[1, 3, 9], [2, 3, 4], [7, 11, 15, 22]]
should return
[1,2,3,3,4,7,9,11,15,22]
Since I like taking advantage of infix operators and higher-order functions where it makes sense to, I would write
infixr 5 ##
(##) :: (Ord a) => [a] -> [a] -> [a]
-- if one side is empty, the merges can only possibly go one way
[] ## ys = ys
xs ## [] = xs
-- otherwise, take the smaller of the two heads out, and continue with the rest
(x:xs) ## (y:ys) = case x `compare` y of
LT -> x : xs ## (y:ys)
EQ -> x : xs ## ys
GT -> y : (x:xs) ## ys
-- a n-way merge can be implemented by a repeated 2-way merge
merge :: (Ord a) => [[a]] -> [a]
merge = foldr1 (##)
Here, xs ## ys merges two lists by their natural ordering (and drops duplicates), while merge [xs, ys, zs..] merges any number of lists.
This leads to the very natural definition of the Hamming numbers:
hamming :: (Num a, Ord a) => [a]
hamming = 1 : map (2*) hamming ## map (3*) hamming ## map (5*) hamming
hamming = 1 : merge [map (n*) hamming | n <- [2, 3, 5]] -- alternative
-- this generates, in order, all numbers of the form 2^i * 3^j * 5^k
-- hamming = [1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36,40,45,48,50,..]
Stealing yairchu's unimplemented idea:
{-# LANGUAGE ViewPatterns #-}
import qualified Data.Map as M
import Data.List (foldl', unfoldr)
import Data.Maybe (mapMaybe)
-- merge any number of ordered lists, dropping duplicate elements
merge :: (Ord a) => [[a]] -> [a]
-- create a map of {n: [tails of lists starting with n]}; then
-- repeatedly take the least n and re-insert the tails
merge = unfoldr ((=<<) step . M.minViewWithKey) . foldl' add M.empty where
add m (x:xs) = M.insertWith' (++) x [xs] m; add m _ = m
step ((x, xss), m) = Just (x, foldl' add m xss)
-- merge any number of ordered lists, preserving duplicate elements
mergeDup :: (Ord a) => [[a]] -> [a]
-- create a map of {(n, i): tail of list number i (which starts with n)}; then
-- repeatedly take the least n and re-insert the tail
-- the index i <- [0..] is used to prevent map from losing duplicates
mergeDup = unfoldr step . M.fromList . mapMaybe swap . zip [0..] where
swap (n, (x:xs)) = Just ((x, n), xs); swap _ = Nothing
step (M.minViewWithKey -> Just (((x, n), xs), m)) =
Just (x, case xs of y:ys -> M.insert (y, n) ys m; _ -> m)
step _ = Nothing
where merge, like my original, eliminates duplicates, while mergeDup preserves them (like Igor's answer).
if efficiency wasn't a concern I'd go with
merge = sort . concat
otherwise:
merge :: Ord a => [[a]] -> [a]
merge [] = []
merge lists =
minVal : merge nextLists
where
heads = map head lists
(minVal, minIdx) = minimum $ zip heads [0..]
(pre, ((_:nextOfMin):post)) = splitAt minIdx lists
nextLists =
if null nextOfMin
then pre ++ post
else pre ++ nextOfMin : post
note however that this implementation always linearly searches for the minimum (while for a large number of list one may wish to maintain a heap etc.)
Unlike the other posts, I would have merge :: [a] -> [a] -> [a]
type SortedList a = [a]
merge :: (Ord a) => SortedList a -> SortedList a -> SortedList a
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
| x < y = x : merge xs (y : ys)
| otherwise = y : merge (x : xs) ys
mergeAll :: (Ord a) => [SortedList a] -> SortedList a
mergeAll = foldr merge []
Just a quick note: if you want to have the optimal log n behavior when merging several lists (such as you'd get with a priority queue), you can do it very easily with a tweak to Igor's beautiful solution above. (I would have put this as a comment on his answer above, but I don't have enough reputation.) In particular, you do:
merge2 pred xs [] = xs
merge2 pred [] ys = ys
merge2 pred (x:xs) (y:ys) =
case pred x y of
True -> x: merge2 pred xs (y:ys)
False -> y: merge2 pred (x:xs) ys
everyother [] = []
everyother e0:[] = e0:[]
everyother (e0:e1:es) = e0:everyother es
merge pred [] = []
merge pred (x:[]) = x
merge pred xs = merge2 pred (merge pred . everyother $ xs)
(merge pred . everyother . tail $ xs)
Note that a real priority queue would be a bit faster/more space efficient, but that this solution is asymptotically just as good and, as I say, has the advantage that it's a very minor tweak to Igor's beautifully clear solution above.
Comments?

Resources