views:

127

answers:

3

So i am given this

intCMP :: Int -> Int -> Ordering
intCMP a b | a == b = EQ
     | a < b = LT
     | otherwise = GT

intCMPRev :: Int -> Int -> Ordering
intCMPRev a b | a == b = EQ
     | a < b = GT
        | otherwise = LT

floatCMP :: Float -> Float -> Ordering
floatCMP a b | a == b = EQ
       | a < b = LT
       | otherwise = GT

I need to write this function

sort3 :: Ord a => (a -> a-> Ordering) -> [a] -> [a]
sort3 cmp xs =

Which will sort 3 or less elements by comparison. No recursion. I was wondering how this works as far as passing say intCMP. Why would you pass that into the sort function? Does it serve a purpose when sorting and returning the sorted list? I'm not really sure how to do the comparisons manually like that without any sort of recursive call, so I'm just trying to understand it better.

I was thinking of doing 3 comparisons and then moving the element to a certain position in the list, but i really don't know how i could even do this in haskell. Any clues on how to start this would be great. Maybe some sort of pattern?

Thanks.

A: 

You're not writing polymorphic functions (which is by definition a function that takes more than one type). Write one first:

cmp :: Ord a => a -> a -> Ordering
cmp x y =
  | x == y = EQ
  | x < y  = LT
  | otherwise = GT

You would write the above that way the functionality that compares the elements in the sort, need not be a part of the sort. To sort a list is by nature recursive: at least if length is undefined. To achieve this simply write a sort that can make use of your custom comparison, here is quick sort though you could write a different type of sort.

sort3 :: (Ord a) => [a] -> [a]  
sort3 [] = []  
sort3 (x:xs) =   
    let smallerSorted = filter (<=)
        biggerSorted = filter(>)
    in  smallerSorted ++ [x] ++ biggerSorted  
Evan Carroll
Sorting an *arbitray* list is naturally recursive, but sorting a list of a specific size (e.g. 3 elements) need not be. You could just write `if x < y and y < z then [x]++[y]++[z} else if ...`
Gabe
"You're not writing polymorphic functions" The signature for the OP's `sort3` function is polymorphic. I think that's what he was referring to.
sepp2k
+2  A: 

Here's a hint:

  • If you have an empty list, clearly the result of sorting it will be an empty list.
  • Likewise, a list with just a single element is also already sorted.
  • If you have a 2-element list, there are only 2 possible orderings, hence only 2 possible return values from your function.
  • If you have a 3-element list, there are 6 possible orderings (the first element can be 1 of 3 input elements, the next element can be 1 of the 2 remaining, leaving only 1 choice for the last element). You can easily write down the 6 different conditions, causing you to return 1 of the 6 possible lists of the 3 elements.
Gabe
I know the algorithm for this problem. Just not sure how to execute it.
Matt
I know the algorithm for this problem. Just not sure how to execute it. So, i want to compare x and y. Then x and c. But while i am doing this i want to move elements around. So if its true for x and y i want to move y to first element position. the new list is now y,x,z from the original. now i want to compare y and z. if its true i want to move z to the first element. z,y,x. Not sure how to compare the new list without using recursion.
Matt
Matt: You don't actually want to *move* elements around during the execution of your algorithm. The algorithm will have a bunch of different code paths, each one resulting in the creation of one of the 6 possible lists of the 3 elements. For example, `if x < y then if y < z then [x, y, z] else if x < z then [x, y, z] else ...`
Gabe
+3  A: 

Partial answer to the first part of your question:

Passing in intCMP to sort3 lets you control the way the sorting is done. Presumably, sort3 intCMP [7,3,6] will return [3,6,7], whereas sort3 intCMPRev [7,3,6] will return [7,6,3]. You could even make your own weird sorting functions like first all the even numbers and then all the odd ones in descending order, like so:

intCMPWeird :: Int -> Int -> Ordering
intCMPWeird a b
    | even a && even b = intCMP a b -- even numbers compare as usual
    | odd a  && odd b  = intCMPRev a b  -- odd numbers compare in reverse order
    | even a && odd b  = LT -- evens are all 'smaller' than odds
    | odd a  && even b = GT -- odds are all 'greater' than evens

Using this, sort3 intCMPWeird [7,3,6] should give [6,7,3].

What happens during typechecking when you pass one of the intCMP... functions into sort3 is (in a very small nutshell) that the compiler tries to match the type of sort3's first argument (a -> a -> Ordering) with the type of the supplied value (Int -> Int -> Ordering) and succeeds in doing that, by making a equal to Int. Then it needs to check whether the constraint Ord a is satisfied for Int, which works! Finally the compiler can figure out that the type of sort3 intCMP is [Int] -> [Int]. Similarly, sort3 floatCMP has type [Float] -> [Float].

I'm not 100% sure why the Ord constraint is on the type of sort3, since you can get the needed information from the passed-in comparison function - are you sure you've typed that correctly?

EDIT: Hint on how to use a where clause to get a readable definition, you still have to fill in some bits and add some more clauses:

sort3 cmp [x,y,z] 
    | x <= y && somethingElse1 = listWithXyzInSomeOrder1
    | x <= z && somethingElse2 = listWithXyzInSomeOrder2
        where a <= b = cmp a b /= GT
yatima2975
Matt
You're on the right track! (Although your example seems a bit strange to me; cmp x y == GT should mean x > y, and y > z should give sort order [z,y,x]).
yatima2975
yea sorry. I have it written down. But i just wrote it out for an example real quick. Ok thanks. I think i have an idea on how to do it.
Matt
There's also a nice trick to make it all more readable, by defining your own <= operator in a where clause, but maybe that's doing too much at once :-) - and you'd only need that for the case with 3 elements in the list; the rest are simple enough.
yatima2975
yea, im not sure how you would do it with where clauses. I just used a bunch of if then statements.
Matt
See the edit in my response.
yatima2975
interesting, ill have to try that. Because we have to create a mergesort function and a fast merge sort function. Difference is when the length of the merge sort list is 3 or less we use sort3. Problem is it actually takes more cycles to do fsort(faster) than msort(mergesort)
Matt
I didn't have time to update my code and try that. I still don't really understand that code either just because you have x and y and then a and b. I'm assuming that's a typo maybe? But in any case thanks for your help. I flew through the rest of the homework after this.
Matt
The part in the `where` clause is a whole new function definition (in this case of the function `<=`), so the a and b there are the arguments of that new function.
yatima2975