fun merge_sort (_, nil) = nil
| merge_sort (_, [a]) = [a]
| merge_sort (f, L) =
let
fun halve nil = (nil,nil)
| halve [a] = ([a], nil)
| halve (a :: b :: rest) =
let
val (x , y) = halve rest
in
(a :: x, b :: y)
end
fun merge (f, nil, x) = x
| merge (f, x, nil) = x
| merge (f, a::b, x::y) =
if f(a, b) then a :: merge (f, b, x::y)
else x :: merge (f, a::b, y);
val (x, y) = halve L
in
merge(f, merge_sort(f, x), merge_sort(f,y))
end;
merge_sort (op <) [2,1,3,2,4,3,45];
This is a SML function that I have been working on. It is meant to take a function call as shown in the bottom and merge sort. Must be one function. I am struggling understanding the pattern matching and how to fully make this function work.
I get this error code when I compile and run it.
$sml < main.sml
Standard ML of New Jersey v110.78 [built: Thu Aug 31 03:45:42 2017]
- val merge_sort = fn : ('a * 'a list -> bool) * 'a list -> 'a list
stdIn:23.1-23.35 Error: operator and operand don't agree [tycon mismatch]
operator domain: ('Z * 'Z list -> bool) * 'Z list
operand: [< ty] * [< ty] -> bool
in expression:
merge_sort <
-
I don't entirely know what I am doing wrong
Using the convention of naming lists with a plural "s" and using the same base name for the head and tail in patterns makes the problem stick out immediately:
merge (f, x::xs, y::ys) =
if f(x, xs) then x :: merge (f, xs, y::ys)
else y :: merge (f, x::xs, ys);
where f(x, xs) should of course be f(x, y).
This convention is conventional because it's useful. Don't leave home without it.
You have a typo; this:
if f(a, b) then a :: merge (f, b, x::y)
else x :: merge (f, a::b, y);
should be this:
if f (a, x) then a :: merge (f, b, x::y)
else x :: merge (f, a::b, y)
(calling f on (a, x) rather than on (a, b)).
Since b and x have different types ('Z list and 'Z, respectively), the consequence of this typo is that f is inferred to have the wrong type ('Z * 'Z list -> bool rather than 'Z * 'Z -> bool), so the whole merge_sort function is inferred to have the wrong type scheme (('a * 'a list -> bool) * 'a list -> 'a list instead of ('a * 'a -> bool) * 'a list -> 'a list).
Some explicit type annotations (e.g. writing f : 'a * 'a -> bool in one place) might make it easier for the compiler to help you see where you're deviating from the types you intended; but, admittedly, if you don't already know where you're deviating, then it can be hard to figure out where to add annotations so the compiler can help you find where you're deviating.
I could not find my code anywhere on the net, so can you please tell me why or why not the function myMergeSort is a mergesort? I know my function myMergeSort sorts, but am not sure if it really sorts using the mergesort algorithm or if it is a different algorithm. I just began with Haskell a few days ago.
merge xs [] = xs
merge [] ys = ys
merge (x : xs) (y : ys)
| x <= y = x : merge xs (y : ys)
| otherwise = y : merge (x : xs) ys
myMergeSort :: [Int] -> [Int]
myMergeSort [] = []
myMergeSort (x:[]) = [x]
myMergeSort (x:xs) = foldl merge [] (map (\x -> [x]) (x:xs))
I have no questions about the merge function.
The following function mergeSortOfficial was the solution presented to us, I understand it but am not sure if I am implementing the mergesort algorithm in my function myMergeSort correctly or not.
Official solution - implemenation:
mergeSortOfficial [] = []
mergeSortOfficial (x : []) = [x]
mergeSortOfficial xs = merge
(mergeSortOfficial (take ((length xs) ‘div‘ 2) xs))
(mergeSortOfficial (drop ((length xs) ‘div‘ 2) xs))
No, that's not mergeSort. That's insertionSort, which is essentially the same algorithm as bubbleSort, depending on how you stare at it. At each step, a singleton list is merged with the accumulated ordered-list-so-far, so, effectively, the element of that singleton is inserted.
As other commenters have already observed, to get mergeSort (and in particular, its efficiency), it's necessary to divide the problem repeatedly into roughly equal parts (rather than "one element" and "the rest"). The "official" solution gives a rather clunky way to do that. I quite like
foldr (\ x (ys, zs) -> (x : zs, ys)) ([], [])
as a way to split a list in two, not in the middle, but into elements in even and odd positions.
If, like me, you like to have structure up front where you can see it, you can make ordered lists a Monoid.
import Data.Monoid
import Data.Foldable
import Control.Newtype
newtype Merge x = Merge {merged :: [x]}
instance Newtype (Merge x) [x] where
pack = Merge
unpack = merged
instance Ord x => Monoid (Merge x) where
mempty = Merge []
mappend (Merge xs) (Merge ys) = Merge (merge xs ys) where
-- merge is as you defined it
And now you have insertion sort just by
ala' Merge foldMap (:[]) :: [x] -> [x]
One way to get the divide-and-conquer structure of mergeSort is to make it a data structure: binary trees.
data Tree x = None | One x | Node (Tree x) (Tree x) deriving Foldable
I haven't enforced a balancing invariant here, but I could. The point is that the same operation as before has another type
ala' Merge foldMap (:[]) :: Tree x -> [x]
which merges lists collected from a treelike arrangement of elements. To obtain said arrangements, think "what's cons for Tree?" and make sure you keep your balance, by the same kind of twistiness I used in the above "dividing" operation.
twistin :: x -> Tree x -> Tree x -- a very cons-like type
twistin x None = One x
twistin x (One y) = Node (One x) (One y)
twistin x (Node l r) = Node (twistin x r) l
Now you have mergeSort by building a binary tree, then merging it.
mergeSort :: Ord x => [x] -> [x]
mergeSort = ala' Merge foldMap (:[]) . foldr twistin None
Of course, introducing the intermediate data structure has curiosity value, but you can easily cut it out and get something like
mergeSort :: Ord x => [x] -> [x]
mergeSort [] = []
mergeSort [x] = [x]
mergeSort xs = merge (mergeSort ys) (mergeSort zs) where
(ys, zs) = foldr (\ x (ys, zs) -> (x : zs, ys)) ([], []) xs
where the tree has become the recursion structure of the program.
myMergeSort is not a correct merge sort. It is a correct insertion sort though. We start with an empty list, then insert the elements one-by-one into the correct position:
myMergeSort [2, 1, 4, 3] ==
foldl merge [] [[2], [1], [4], [3]] ==
((([] `merge` [2]) `merge` [1]) `merge` [4]) `merge` [3] ==
(([2] `merge` [1]) `merge` [4]) `merge` [3]
([1, 2] `merge` [4]) `merge` [3] ==
[1, 2, 4] `merge` [3] ==
[1, 2, 3, 4]
Since each insertion takes linear time, the whole sort is quadratic.
mergeSortOfficial is technically right, but it's inefficient. length takes linear time, and it's called at each level of recursion for the total length of the list. take and drop are also linear. The overall complexity remains the optimal n * log n, but we run a couple of unnecessary circles.
If we stick to top-down merging, we could do better with splitting the list to a list of elements with even indices and another with odd indices. Splitting is still linear, but it's only a single traversal instead of two (length and then take / drop in the official sort).
split :: [a] -> ([a], [a])
split = go [] [] where
go as bs [] = (as, bs)
go as bs (x:xs) = go (x:bs) as xs
mergeSortOfficial :: [Int] -> [Int]
mergeSortOfficial [] = []
mergeSortOfficial (x : []) = [x]
mergeSortOfficial xs =
let (as, bs) = split xs in
merge (mergeSortOfficial as) (mergeSortOfficial bs)
As WillNess noted in the comments, the above split yields an unstable sort. We can use a stable alternative:
import Control.Arrow
stableSplit :: [a] -> ([a], [a])
stableSplit xs = go xs xs where
go (x:xs) (_:_:ys) = first (x:) (go xs ys)
go xs ys = ([], xs)
The best way is probably doing a bottom-up merge. It's the approach the sort in Data.List takes. Here we merge consecutive pairs of lists until there is only a single list left:
mergeSort :: Ord a => [a] -> [a]
mergeSort [] = []
mergeSort xs = mergeAll (map (:[]) xs) where
mergePairs (x:y:ys) = merge x y : mergePairs ys
mergePairs xs = xs
mergeAll [xs] = xs
mergeAll xs = mergeAll (mergePairs xs)
Data.List.sort works largely the same as above, except it starts with finding descending and ascending runs in the input instead of just creating singleton lists from the elements.
This matrix transposition function works, but I'm trying to understand its step by step execurtion and I don't get it.
transpose:: [[a]]->[[a]]
transpose ([]:_) = []
transpose x = (map head x) : transpose (map tail x)
with
transpose [[1,2,3],[4,5,6],[7,8,9]]
it returns:
[[1,4,7],[2,5,8],[3,6,9]]
I don't get how the concatenation operator is working with map. It is concatenating each head of x in the same function call? How?
is this
(map head x)
creating a list of the head elements of each list?
Let's look at what the function does for your example input:
transpose [[1,2,3],[4,5,6],[7,8,9]]
<=>
(map head [[1,2,3],[4,5,6],[7,8,9]]) : (transpose (map tail [[1,2,3],[4,5,6],[7,8,9]]))
<=>
[1,4,7] : (transpose [[2,3],[5,6],[8,9]])
<=>
[1,4,7] : (map head [[2,3],[5,6],[8,9]]) : (transpose (map tail [[2,3],[5,6],[8,9]]))
<=>
[1,4,7] : [2,5,8] : (transpose [[3],[6],[9]])
<=>
[1,4,7] : [2,5,8] : (map head [[3],[6],[9]]) : (transpose (map tail [[3],[6],[9]]))
<=>
[1,4,7] : [2,5,8] : [3, 6, 9] : (transpose [[], [], []])
<=>
[1,4,7] : [2,5,8] : [3, 6, 9] : [] -- because transpose ([]:_) = []
<=>
[[1,4,7],[2,5,8],[3,6,9]]
Note that the order in which I chose to reduce the terms, is not the same as the evaluation order haskell will use, but that does not change the result.
Edit: In response to your edited question:
is this
(map head x)
creating a list of the head elements of each list?
Yes, it is.
The cons operator : attach an object of type a to a list of type [a]. In
(map head x) : transpose (map tail x)
The LHS is a list (a = [b]), while the RHS is a list of list ([a] = [[b]]), so such a construction is valid. The result is
[x,y,z,...] : [[a,b,...],[d,e,...],...] = [[x,y,z,...], [a,b,...],[d,e,...],...]
In your case, map head x and map tail x splits the matrix
x = [[1,2,3],[4,5,6],[7,8,9]]
into
map head x = [1,4,7]
map tail x = [[2,3],[5,6],[8,9]]
(and yes, map head x is a list of the head elements of each list.) The 2nd part is transposed (for detail steps see #sepp2k's answer) to form
transpose (map tail x) = [[2,5,8],[3,6,9]]
so cons-ing [1,4,7] to this gives
map head x : transpose (map tail x) = [1,4,7] : [[2,5,8],[3,6,9]]
= [[1,4,7] , [2,5,8],[3,6,9]]
ghci is your friend:
*Main> :t map head
map head :: [[a]] -> [a]
*Main> :t map tail
map tail :: [[a]] -> [[a]]
Even if you don't understand map (a problem you'd want to correct quickly!), the types of these expressions tell much about how they work. The first is a single list taken from a list of lists, so let's feed a simple vector to it to see what happens.
You might want to write
*Main> map head [1,2,3]
but that fails to typecheck:
<interactive>:1:14:
No instance for (Num [a])
arising from the literal `3' at :1:14
Possible fix: add an instance declaration for (Num [a])
In the expression: 3
In the second argument of `map', namely `[1, 2, 3]'
In the expression: map head [1, 2, 3]
Remember, the argument's type is a list of lists, so
*Main> map head [[1,2,3]]
[1]
Getting a bit more complex
*Main> map head [[1,2,3],[4,5,6]]
[1,4]
Doing the same but with tail instead of head gives
*Main> map tail [[1,2,3],[4,5,6]]
[[2,3],[5,6]]
As you can see, the definition of transpose is repeatedly slicing off the first “row” with map head x and transposing the rest, which is map tail x.
These things are the same:
map head xxs
map (\xs -> head xs) xxs
It's lambda-expression, which means i return the head of xs for every xs
Example:
map head [[1,2,3],[4,5,6],[7,8,9]]
-> map (\xs -> head xs) [[1,2,3],[4,5,6],[7,8,9]]
-> [head [1,2,3], head [4,5,6], head [7,8,9]]
-> [1,4,7]
It's simple
By the way, this function doesn't work when given an input like [[1,2,3], [], [1,2]]. However, the transpose function from Data.List will accept this input, and return [[1,1], [2,2], [3]].
When we are calling the recursive transpose code, we need to get rid of the [].
In case you want to transpose rectangular arrays using head and tail, making sure that the number of columns is the same beforehand, then you can do the following:
rectangularTranspose :: [[a]] -> [[a]]
rectangularTranspose m = rectTrans m []
where
rectTrans [] a = a
rectTrans ([]:xss) a = rectTrans xss a
rectTrans ((x:xs):xss) a = rectTrans a ((x:map head xss): rectTrans (xs:map tail xss) a)
It works for square arrays and singletons too, obviously, but I don't see much use in this when the standard implementation gives you more options.
Alternatively, you could just define your own function. I found a simpler way to implement matrix transpose in Haskell using only list comprehension. It works for a generic m* n matrix with non-empty elements
transpose' :: [[a]] -> [[a]]
transpose' xss = chop nrows [xs !! (j-1) | i <- [1..ncols], j <- take nrows [i, i+ncols ..]]
where nrows = length xss
ncols = length(head xss)
xs = concat xss
chop :: Int -> [a] -> [[a]]
chop _ [] = []
chop n xs = take n xs : chop n (drop n xs)