1

First off, I would like to make you all aware that I'm very new to Haskell, so to increase knowledge etc, I've been trying out questions and I'm pretty stuck on one. I think I'm nearly there but some more experienced advice would be appreciated. Here's the question:

A sporting team is represented by it's name and the amount of points they scored in their last games like so ("Newcastle",[3,3,3,0]). This data is modelled by the type definitions:

type TName = String
type Points = [Int]
type Team = (TName,Points)

From this I have to define the following function that orders one team higher than another if their points sum is greater:

sortPoints :: [Team] -> [Team]

This is what I've tried:

sortPoints :: [Team] -> [Team]
sortPoints [_,()] -> []
sortPoints [_,(x:xs)] = sum[x|x<-xs]

Once I get to here, I'm not too sure how to go about adding the conditions to check the points sum, any pointers would be greatly appreciated as I'm still coming to terms with a lot of Haskell features.

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
Steven H
  • 11
  • 3
  • 6
    have a look at [hoogle](https://www.haskell.org/hoogle/?hoogle=compare) and search for: `sortBy`, `compare`, `on` and `snd` - you can puzzle those together to get exactly what you want (by puzzle together I really am talking about *composing* ) – Random Dev Jul 31 '15 at 10:52
  • @Carsten: That could have been an answer. :D – Zeta Jul 31 '15 at 12:11
  • @Zeta yours has a bit more info though ;) (+1) – Random Dev Jul 31 '15 at 13:16
  • @Carsten: Still, this is getting into a habit: you [post a comment](http://stackoverflow.com/questions/30612654/hspec-nothing-expectation-failing-to-compile/30617137#comment49292172_30612654), and I write a community wiki answer based on that comment :D. – Zeta Aug 01 '15 at 01:22

1 Answers1

7

Note: This post is written in literate Haskell. You can save it as Team.lhs and try it. That being said, it's basically a longer version of Carsten's comment. If you still try to figure things out, use hoogle and look for the functions, although it's fine if you manage things with sortBy solely first.


First of all, we're going to work on lists, so you want to import Data.List.

> module Team where
> import Data.List

It contains a function called sortBy:

sortBy :: (a -> a -> Ordering) -> [a] -> [a]

The first argument of sortBy should be a function that compares two elements of your list and returns

  • LT if the first is less than the second,
  • EQ if the both are equal,
  • GT if the first is greater than the second.

So we need something that that takes two teams and returns their ordering:

> -- Repeating your types for completeness
> type TName  = String
> type Points = [Int]
> type Team   = (TName, Points)
>
> compareTeams :: Team -> Team -> Ordering

Now, you want to compare teams based on their sum of their points. You don't need their name, so you can capture just the second part of the pair:

> compareTeams (_, s1) (_, s2) =

We need the sum of the points, so we define sum1 and sum2 to be the respective sums of the teams:

>       let sum1 = sum s1
>           sum2 = sum s2

Now we can compare those sums:

        in if sum1 < sum2 
             then LT
             else if sum1 == sum2 
                     then EQ
                     else GT

However, that's rather verbose, and there's already a function that has type Ord a => a -> a -> Ordering. It's called compare and part of the Prelude:

>       in sum1 `compare` sum2

That's a lot more concise. Now we can define sortTeams easily:

> sortTeams :: [Team] -> [Team]
> sortTeams = sortBy compareTeams

And that's it, we're done!


Fine, I lied, we're not 100% done. The module Data.Ord contains a function called comparing that's rather handy:

comparing :: Ord b => (a -> b) -> a -> a -> Ordering
comparing f x y = f x `compare` f y -- or similar

Together with snd and sum you can define sortTeams in a single line:

sortTeams = sortBy (comparing $ sum . snd)

The alternative on mentioned by Carsten is on from Data.Function:

sortTeams = sortBy (compare `on` sum . snd)
Luis Casillas
  • 29,802
  • 7
  • 49
  • 102
Zeta
  • 103,620
  • 13
  • 194
  • 236