
I'm having real trouble starting this project. Basically I have to create a record store that store information about artists and albums and also the number of sales that they have had. It also needs to generate a list of the top 5 sellers. So far I have: recordSale :: Sales -> String -> String -> Sales where recordSale sales anArtist aTrack returns a modified version of the sales. Any help getting started on this would be gratefully received. I don't want answers, I just want help getting started. Thank you -- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29046956.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

Firstly, do you mean "recordSale sales anArtist anAlbum" ?
First off consider a datatype to model albums - something like:
type Name = String
type Artist = String
type Sold = Int
data Album = Album Name Sold
And consider storing then in a hash [1] where the artist name is the
key and [Album] is the value.
-deech
[1] http://www.haskell.org/ghc/docs/6.12.2/html/libraries/containers-0.3.0.0/Dat...
On Thu, Jul 1, 2010 at 2:56 PM, Mrwibbly
I'm having real trouble starting this project. Basically I have to create a record store that store information about artists and albums and also the number of sales that they have had. It also needs to generate a list of the top 5 sellers.
So far I have: recordSale :: Sales -> String -> String -> Sales
where recordSale sales anArtist aTrack returns a modified version of the sales.
Any help getting started on this would be gratefully received. I don't want answers, I just want help getting started.
Thank you -- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29046956.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Am 01.07.2010 um 21:56 schrieb Mrwibbly:
I'm having real trouble starting this project. Basically I have to create a record store that store information about artists and albums and also the number of sales that they have had. It also needs to generate a list of the top 5 sellers.
So far I have: recordSale :: Sales -> String -> String -> Sales
where recordSale sales anArtist aTrack returns a modified version of the sales.
Any help getting started on this would be gratefully received. I don't want answers, I just want help getting started.
First, I would state explicitly what a record is: It is a tuple of an artist's name and a record's name type Record = (String, String) Now function recordSale has type recordSale :: Sales -> Record -> Sales This is the an "uncurried" equivalent of your definition. You can read it as "from a sales object you get to another sales object via a (sold) record". That already seems to be a good abstraction, but we can do better: If you flip the arguments, you get recordSale :: Record -> Sales -> Sales Now you can create a sale (recordSale ("Zappa", "Apostrophe")). This sale is a function of type (Sales -> Sales) that modifies your sales. We state this by defining type Sale = Sales -> Sales recordSale :: Record -> Sale Sales can be concatenated with the dot operator (.) and there is even a "neutral sale", the function 'id'. Thus, you know immediately that for any sales x,y,z there is (x . (y . z) == (x . y) . z) and (x . id == x). In other words, it forms a monoid - just like the number of sales together with (+) and 0! If you're only interested in the number of sales, you can simply define type Sales = Integer recordSale record sales = sales + 1 But you don't want to keep track of the whole number of sales - you want a number for every record you have sold. That means, you need a data structure that maps records to their number of sales: import Data.Map type Sales = Map Record Integer It's a bit tricky to find an implementation for recordSale. Think of how you can combine two arbitrary Sales objects before you try to implement it. Regards, Holger

This really helped, but now I am trying to add a new track to the database using a menu but it won't compile. I have tried a lot of different things but to no avail. When I get rid of the menu I am able to run, for example, newRecord "This Charming Man" "The Smiths" 1 [] This adds the data to an empty database but I can't seem to call newRecord again and add another record to the existing database. Thanks for your help previously, Jack type Title = String type Artist = String type Sold = Int type Sales = Sales Record type Record = (Title, Artist, Sold) testDatabase :: [Sales] testDatabase = [(Sales "Jack" "Waters" 2)] --recordSale :: Sales -> String -> String -> Sales --recordSale title artist = (title, artist) newRecord :: Record -> [Sales] -> [Sales] newRecord title artist sold dbase = (title, artist, sold):dbase recordSale :: Record -> [Sales] recordSale record sales = sold + 1 main :: [Sales] -> IO() main dbase = do putStrLn "1 = Add a new record: " input <- getLine let x = read input :: Int if x == 1 then do putStrLn "Please enter a title: " title <- getLine putStrLn "Please enter an artist name: " artist <- getLine putStrLn "Please enter the number sales: " sales <- getInt newRecord (Sales title artist sales []) dbase Holger Siegel wrote:
Am 01.07.2010 um 21:56 schrieb Mrwibbly:
I'm having real trouble starting this project. Basically I have to create a record store that store information about artists and albums and also the number of sales that they have had. It also needs to generate a list of the top 5 sellers.
So far I have: recordSale :: Sales -> String -> String -> Sales
where recordSale sales anArtist aTrack returns a modified version of the sales.
Any help getting started on this would be gratefully received. I don't want answers, I just want help getting started.
First, I would state explicitly what a record is: It is a tuple of an artist's name and a record's name
type Record = (String, String)
Now function recordSale has type
recordSale :: Sales -> Record -> Sales
This is the an "uncurried" equivalent of your definition. You can read it as "from a sales object you get to another sales object via a (sold) record". That already seems to be a good abstraction, but we can do better: If you flip the arguments, you get
recordSale :: Record -> Sales -> Sales
Now you can create a sale (recordSale ("Zappa", "Apostrophe")). This sale is a function of type (Sales -> Sales) that modifies your sales. We state this by defining
type Sale = Sales -> Sales
recordSale :: Record -> Sale
Sales can be concatenated with the dot operator (.) and there is even a "neutral sale", the function 'id'. Thus, you know immediately that for any sales x,y,z there is (x . (y . z) == (x . y) . z) and (x . id == x). In other words, it forms a monoid - just like the number of sales together with (+) and 0!
If you're only interested in the number of sales, you can simply define
type Sales = Integer
recordSale record sales = sales + 1
But you don't want to keep track of the whole number of sales - you want a number for every record you have sold. That means, you need a data structure that maps records to their number of sales:
import Data.Map
type Sales = Map Record Integer
It's a bit tricky to find an implementation for recordSale. Think of how you can combine two arbitrary Sales objects before you try to implement it.
Regards, Holger
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29073993.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

Does this code compile? The line "type Sales = Sales Record" for
instance is wrong - it should be "data Sales = Sales Record".
Additionally "recordSale" returns an Int, not [Sales].
-deech
On Mon, Jul 5, 2010 at 10:50 AM, Mrwibbly
This really helped, but now I am trying to add a new track to the database using a menu but it won't compile. I have tried a lot of different things but to no avail.
When I get rid of the menu I am able to run, for example, newRecord "This Charming Man" "The Smiths" 1 []
This adds the data to an empty database but I can't seem to call newRecord again and add another record to the existing database.
Thanks for your help previously,
Jack
type Title = String type Artist = String type Sold = Int type Sales = Sales Record type Record = (Title, Artist, Sold)
testDatabase :: [Sales] testDatabase = [(Sales "Jack" "Waters" 2)]
--recordSale :: Sales -> String -> String -> Sales --recordSale title artist = (title, artist)
newRecord :: Record -> [Sales] -> [Sales] newRecord title artist sold dbase = (title, artist, sold):dbase
recordSale :: Record -> [Sales] recordSale record sales = sold + 1
main :: [Sales] -> IO() main dbase = do putStrLn "1 = Add a new record: " input <- getLine let x = read input :: Int if x == 1 then do putStrLn "Please enter a title: " title <- getLine putStrLn "Please enter an artist name: " artist <- getLine putStrLn "Please enter the number sales: " sales <- getInt newRecord (Sales title artist sales []) dbase
Holger Siegel wrote:
Am 01.07.2010 um 21:56 schrieb Mrwibbly:
I'm having real trouble starting this project. Basically I have to create a record store that store information about artists and albums and also the number of sales that they have had. It also needs to generate a list of the top 5 sellers.
So far I have: recordSale :: Sales -> String -> String -> Sales
where recordSale sales anArtist aTrack returns a modified version of the sales.
Any help getting started on this would be gratefully received. I don't want answers, I just want help getting started.
First, I would state explicitly what a record is: It is a tuple of an artist's name and a record's name
type Record = (String, String)
Now function recordSale has type
recordSale :: Sales -> Record -> Sales
This is the an "uncurried" equivalent of your definition. You can read it as "from a sales object you get to another sales object via a (sold) record". That already seems to be a good abstraction, but we can do better: If you flip the arguments, you get
recordSale :: Record -> Sales -> Sales
Now you can create a sale (recordSale ("Zappa", "Apostrophe")). This sale is a function of type (Sales -> Sales) that modifies your sales. We state this by defining
type Sale = Sales -> Sales
recordSale :: Record -> Sale
Sales can be concatenated with the dot operator (.) and there is even a "neutral sale", the function 'id'. Thus, you know immediately that for any sales x,y,z there is (x . (y . z) == (x . y) . z) and (x . id == x). In other words, it forms a monoid - just like the number of sales together with (+) and 0!
If you're only interested in the number of sales, you can simply define
type Sales = Integer
recordSale record sales = sales + 1
But you don't want to keep track of the whole number of sales - you want a number for every record you have sold. That means, you need a data structure that maps records to their number of sales:
import Data.Map
type Sales = Map Record Integer
It's a bit tricky to find an implementation for recordSale. Think of how you can combine two arbitrary Sales objects before you try to implement it.
Regards, Holger
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29073993.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

You said it didn't compile. I somehow missed that , sorry.
-deech
On Mon, Jul 5, 2010 at 11:06 AM, aditya siram
Does this code compile? The line "type Sales = Sales Record" for instance is wrong - it should be "data Sales = Sales Record". Additionally "recordSale" returns an Int, not [Sales].
-deech
On Mon, Jul 5, 2010 at 10:50 AM, Mrwibbly
wrote: This really helped, but now I am trying to add a new track to the database using a menu but it won't compile. I have tried a lot of different things but to no avail.
When I get rid of the menu I am able to run, for example, newRecord "This Charming Man" "The Smiths" 1 []
This adds the data to an empty database but I can't seem to call newRecord again and add another record to the existing database.
Thanks for your help previously,
Jack
type Title = String type Artist = String type Sold = Int type Sales = Sales Record type Record = (Title, Artist, Sold)
testDatabase :: [Sales] testDatabase = [(Sales "Jack" "Waters" 2)]
--recordSale :: Sales -> String -> String -> Sales --recordSale title artist = (title, artist)
newRecord :: Record -> [Sales] -> [Sales] newRecord title artist sold dbase = (title, artist, sold):dbase
recordSale :: Record -> [Sales] recordSale record sales = sold + 1
main :: [Sales] -> IO() main dbase = do putStrLn "1 = Add a new record: " input <- getLine let x = read input :: Int if x == 1 then do putStrLn "Please enter a title: " title <- getLine putStrLn "Please enter an artist name: " artist <- getLine putStrLn "Please enter the number sales: " sales <- getInt newRecord (Sales title artist sales []) dbase
Holger Siegel wrote:
Am 01.07.2010 um 21:56 schrieb Mrwibbly:
I'm having real trouble starting this project. Basically I have to create a record store that store information about artists and albums and also the number of sales that they have had. It also needs to generate a list of the top 5 sellers.
So far I have: recordSale :: Sales -> String -> String -> Sales
where recordSale sales anArtist aTrack returns a modified version of the sales.
Any help getting started on this would be gratefully received. I don't want answers, I just want help getting started.
First, I would state explicitly what a record is: It is a tuple of an artist's name and a record's name
type Record = (String, String)
Now function recordSale has type
recordSale :: Sales -> Record -> Sales
This is the an "uncurried" equivalent of your definition. You can read it as "from a sales object you get to another sales object via a (sold) record". That already seems to be a good abstraction, but we can do better: If you flip the arguments, you get
recordSale :: Record -> Sales -> Sales
Now you can create a sale (recordSale ("Zappa", "Apostrophe")). This sale is a function of type (Sales -> Sales) that modifies your sales. We state this by defining
type Sale = Sales -> Sales
recordSale :: Record -> Sale
Sales can be concatenated with the dot operator (.) and there is even a "neutral sale", the function 'id'. Thus, you know immediately that for any sales x,y,z there is (x . (y . z) == (x . y) . z) and (x . id == x). In other words, it forms a monoid - just like the number of sales together with (+) and 0!
If you're only interested in the number of sales, you can simply define
type Sales = Integer
recordSale record sales = sales + 1
But you don't want to keep track of the whole number of sales - you want a number for every record you have sold. That means, you need a data structure that maps records to their number of sales:
import Data.Map
type Sales = Map Record Integer
It's a bit tricky to find an implementation for recordSale. Think of how you can combine two arbitrary Sales objects before you try to implement it.
Regards, Holger
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29073993.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I changed that line to say type Sales = Sales Record. But unfortunately it still fails to compile. Do you have any idea why this might be the case? -Jack aditya siram-2 wrote:
You said it didn't compile. I somehow missed that , sorry. -deech
On Mon, Jul 5, 2010 at 11:06 AM, aditya siram
wrote: Does this code compile? The line "type Sales = Sales Record" for instance is wrong - it should be "data Sales = Sales Record". Additionally "recordSale" returns an Int, not [Sales].
-deech
On Mon, Jul 5, 2010 at 10:50 AM, Mrwibbly
wrote: This really helped, but now I am trying to add a new track to the database using a menu but it won't compile. I have tried a lot of different things but to no avail.
When I get rid of the menu I am able to run, for example, newRecord "This Charming Man" "The Smiths" 1 []
This adds the data to an empty database but I can't seem to call newRecord again and add another record to the existing database.
Thanks for your help previously,
Jack
type Title = String type Artist = String type Sold = Int type Sales = Sales Record type Record = (Title, Artist, Sold)
testDatabase :: [Sales] testDatabase = [(Sales "Jack" "Waters" 2)]
--recordSale :: Sales -> String -> String -> Sales --recordSale title artist = (title, artist)
newRecord :: Record -> [Sales] -> [Sales] newRecord title artist sold dbase = (title, artist, sold):dbase
recordSale :: Record -> [Sales] recordSale record sales = sold + 1
main :: [Sales] -> IO() main dbase = do putStrLn "1 = Add a new record: " input <- getLine let x = read input :: Int if x == 1 then do putStrLn "Please enter a title: " title <- getLine putStrLn "Please enter an artist name: " artist <- getLine putStrLn "Please enter the number sales: " sales <- getInt newRecord (Sales title artist sales []) dbase
Holger Siegel wrote:
Am 01.07.2010 um 21:56 schrieb Mrwibbly:
I'm having real trouble starting this project. Basically I have to create a record store that store information about artists and albums and also the number of sales that they have had. It also needs to generate a list of the top 5 sellers.
So far I have: recordSale :: Sales -> String -> String -> Sales
where recordSale sales anArtist aTrack returns a modified version of the sales.
Any help getting started on this would be gratefully received. I don't want answers, I just want help getting started.
First, I would state explicitly what a record is: It is a tuple of an artist's name and a record's name
type Record = (String, String)
Now function recordSale has type
recordSale :: Sales -> Record -> Sales
This is the an "uncurried" equivalent of your definition. You can read it as "from a sales object you get to another sales object via a (sold) record". That already seems to be a good abstraction, but we can do better: If you flip the arguments, you get
recordSale :: Record -> Sales -> Sales
Now you can create a sale (recordSale ("Zappa", "Apostrophe")). This sale is a function of type (Sales -> Sales) that modifies your sales. We state this by defining
type Sale = Sales -> Sales
recordSale :: Record -> Sale
Sales can be concatenated with the dot operator (.) and there is even a "neutral sale", the function 'id'. Thus, you know immediately that for any sales x,y,z there is (x . (y . z) == (x . y) . z) and (x . id == x). In other words, it forms a monoid - just like the number of sales together with (+) and 0!
If you're only interested in the number of sales, you can simply define
type Sales = Integer
recordSale record sales = sales + 1
But you don't want to keep track of the whole number of sales - you want a number for every record you have sold. That means, you need a data structure that maps records to their number of sales:
import Data.Map
type Sales = Map Record Integer
It's a bit tricky to find an implementation for recordSale. Think of how you can combine two arbitrary Sales objects before you try to implement it.
Regards, Holger
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29073993.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29077121.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

Yes there are a few more problems. Instead of point out each one here
is some modified code that does compile. Compare it to what you have
and let me know if you have questions:
type Title = String
type Artist = String
type Sold = Int
type Record = (Title, (Artist, Sold))
testDatabase :: [Record]
testDatabase = [("Jack", ("Waters", 2))]
newRecord :: Record -> [Record] -> [Record]
newRecord record dbase = [record] ++ dbase
getTitle :: Record -> Title
getTitle (title,_) = title
addSale :: Record -> Record
addSale (title, (artist,sold)) = (title, (artist, sold + 1))
recordSale :: Record -> [Record] -> [Record]
recordSale r@(title, (artist,sold)) sales =
case (Prelude.lookup title sales) of
Nothing -> error "This record does not exist"
Just x -> [addSale r] ++ (filter (\a -> (getTitle a) /= title) sales)
addRecord :: IO Record
addRecord = do
putStrLn "Please enter a title: "
title <- getLine
putStrLn "Please enter an artist name: "
artist <- getLine
putStrLn "Please enter the number sales: "
sales <- getInt
return (title , (artist, sales))
where
getInt :: IO Int
getInt = getLine >>= return . read
On Mon, Jul 5, 2010 at 11:36 AM, Mrwibbly
I changed that line to say type Sales = Sales Record. But unfortunately it still fails to compile. Do you have any idea why this might be the case?
-Jack
aditya siram-2 wrote:
You said it didn't compile. I somehow missed that , sorry. -deech
On Mon, Jul 5, 2010 at 11:06 AM, aditya siram
wrote: Does this code compile? The line "type Sales = Sales Record" for instance is wrong - it should be "data Sales = Sales Record". Additionally "recordSale" returns an Int, not [Sales].
-deech
On Mon, Jul 5, 2010 at 10:50 AM, Mrwibbly
wrote: This really helped, but now I am trying to add a new track to the database using a menu but it won't compile. I have tried a lot of different things but to no avail.
When I get rid of the menu I am able to run, for example, newRecord "This Charming Man" "The Smiths" 1 []
This adds the data to an empty database but I can't seem to call newRecord again and add another record to the existing database.
Thanks for your help previously,
Jack
type Title = String type Artist = String type Sold = Int type Sales = Sales Record type Record = (Title, Artist, Sold)
testDatabase :: [Sales] testDatabase = [(Sales "Jack" "Waters" 2)]
--recordSale :: Sales -> String -> String -> Sales --recordSale title artist = (title, artist)
newRecord :: Record -> [Sales] -> [Sales] newRecord title artist sold dbase = (title, artist, sold):dbase
recordSale :: Record -> [Sales] recordSale record sales = sold + 1
main :: [Sales] -> IO() main dbase = do putStrLn "1 = Add a new record: " input <- getLine let x = read input :: Int if x == 1 then do putStrLn "Please enter a title: " title <- getLine putStrLn "Please enter an artist name: " artist <- getLine putStrLn "Please enter the number sales: " sales <- getInt newRecord (Sales title artist sales []) dbase
Holger Siegel wrote:
Am 01.07.2010 um 21:56 schrieb Mrwibbly:
I'm having real trouble starting this project. Basically I have to create a record store that store information about artists and albums and also the number of sales that they have had. It also needs to generate a list of the top 5 sellers.
So far I have: recordSale :: Sales -> String -> String -> Sales
where recordSale sales anArtist aTrack returns a modified version of the sales.
Any help getting started on this would be gratefully received. I don't want answers, I just want help getting started.
First, I would state explicitly what a record is: It is a tuple of an artist's name and a record's name
type Record = (String, String)
Now function recordSale has type
recordSale :: Sales -> Record -> Sales
This is the an "uncurried" equivalent of your definition. You can read it as "from a sales object you get to another sales object via a (sold) record". That already seems to be a good abstraction, but we can do better: If you flip the arguments, you get
recordSale :: Record -> Sales -> Sales
Now you can create a sale (recordSale ("Zappa", "Apostrophe")). This sale is a function of type (Sales -> Sales) that modifies your sales. We state this by defining
type Sale = Sales -> Sales
recordSale :: Record -> Sale
Sales can be concatenated with the dot operator (.) and there is even a "neutral sale", the function 'id'. Thus, you know immediately that for any sales x,y,z there is (x . (y . z) == (x . y) . z) and (x . id == x). In other words, it forms a monoid - just like the number of sales together with (+) and 0!
If you're only interested in the number of sales, you can simply define
type Sales = Integer
recordSale record sales = sales + 1
But you don't want to keep track of the whole number of sales - you want a number for every record you have sold. That means, you need a data structure that maps records to their number of sales:
import Data.Map
type Sales = Map Record Integer
It's a bit tricky to find an implementation for recordSale. Think of how you can combine two arbitrary Sales objects before you try to implement it.
Regards, Holger
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29073993.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29077121.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

And here's a more sane version of recordSale:
recordSale' :: Title -> [Record] -> [Record]
recordSale' title sales =
case (Prelude.lookup title sales) of
Nothing -> error "This record does not exist"
Just x -> [addSale (title,x)] ++ (filter (\a -> (getTitle a) /=
title) sales)
-deech
On Mon, Jul 5, 2010 at 11:39 AM, aditya siram
Yes there are a few more problems. Instead of point out each one here is some modified code that does compile. Compare it to what you have and let me know if you have questions:
type Title = String type Artist = String type Sold = Int type Record = (Title, (Artist, Sold))
testDatabase :: [Record] testDatabase = [("Jack", ("Waters", 2))]
newRecord :: Record -> [Record] -> [Record] newRecord record dbase = [record] ++ dbase
getTitle :: Record -> Title getTitle (title,_) = title
addSale :: Record -> Record addSale (title, (artist,sold)) = (title, (artist, sold + 1))
recordSale :: Record -> [Record] -> [Record] recordSale r@(title, (artist,sold)) sales = case (Prelude.lookup title sales) of Nothing -> error "This record does not exist" Just x -> [addSale r] ++ (filter (\a -> (getTitle a) /= title) sales)
addRecord :: IO Record addRecord = do putStrLn "Please enter a title: " title <- getLine putStrLn "Please enter an artist name: " artist <- getLine putStrLn "Please enter the number sales: " sales <- getInt return (title , (artist, sales)) where getInt :: IO Int getInt = getLine >>= return . read
On Mon, Jul 5, 2010 at 11:36 AM, Mrwibbly
wrote: I changed that line to say type Sales = Sales Record. But unfortunately it still fails to compile. Do you have any idea why this might be the case?
-Jack
aditya siram-2 wrote:
You said it didn't compile. I somehow missed that , sorry. -deech
On Mon, Jul 5, 2010 at 11:06 AM, aditya siram
wrote: Does this code compile? The line "type Sales = Sales Record" for instance is wrong - it should be "data Sales = Sales Record". Additionally "recordSale" returns an Int, not [Sales].
-deech
On Mon, Jul 5, 2010 at 10:50 AM, Mrwibbly
wrote: This really helped, but now I am trying to add a new track to the database using a menu but it won't compile. I have tried a lot of different things but to no avail.
When I get rid of the menu I am able to run, for example, newRecord "This Charming Man" "The Smiths" 1 []
This adds the data to an empty database but I can't seem to call newRecord again and add another record to the existing database.
Thanks for your help previously,
Jack
type Title = String type Artist = String type Sold = Int type Sales = Sales Record type Record = (Title, Artist, Sold)
testDatabase :: [Sales] testDatabase = [(Sales "Jack" "Waters" 2)]
--recordSale :: Sales -> String -> String -> Sales --recordSale title artist = (title, artist)
newRecord :: Record -> [Sales] -> [Sales] newRecord title artist sold dbase = (title, artist, sold):dbase
recordSale :: Record -> [Sales] recordSale record sales = sold + 1
main :: [Sales] -> IO() main dbase = do putStrLn "1 = Add a new record: " input <- getLine let x = read input :: Int if x == 1 then do putStrLn "Please enter a title: " title <- getLine putStrLn "Please enter an artist name: " artist <- getLine putStrLn "Please enter the number sales: " sales <- getInt newRecord (Sales title artist sales []) dbase
Holger Siegel wrote:
Am 01.07.2010 um 21:56 schrieb Mrwibbly:
> > I'm having real trouble starting this project. Basically I have to > create > a > record store that store information about artists and albums and also > the > number of sales that they have had. It also needs to generate a list > of > the > top 5 sellers. > > So far I have: recordSale :: Sales -> String -> String -> Sales > > where recordSale sales anArtist aTrack returns a modified version of > the > sales. > > Any help getting started on this would be gratefully received. I don't > want > answers, I just want help getting started.
First, I would state explicitly what a record is: It is a tuple of an artist's name and a record's name
type Record = (String, String)
Now function recordSale has type
recordSale :: Sales -> Record -> Sales
This is the an "uncurried" equivalent of your definition. You can read it as "from a sales object you get to another sales object via a (sold) record". That already seems to be a good abstraction, but we can do better: If you flip the arguments, you get
recordSale :: Record -> Sales -> Sales
Now you can create a sale (recordSale ("Zappa", "Apostrophe")). This sale is a function of type (Sales -> Sales) that modifies your sales. We state this by defining
type Sale = Sales -> Sales
recordSale :: Record -> Sale
Sales can be concatenated with the dot operator (.) and there is even a "neutral sale", the function 'id'. Thus, you know immediately that for any sales x,y,z there is (x . (y . z) == (x . y) . z) and (x . id == x). In other words, it forms a monoid - just like the number of sales together with (+) and 0!
If you're only interested in the number of sales, you can simply define
type Sales = Integer
recordSale record sales = sales + 1
But you don't want to keep track of the whole number of sales - you want a number for every record you have sold. That means, you need a data structure that maps records to their number of sales:
import Data.Map
type Sales = Map Record Integer
It's a bit tricky to find an implementation for recordSale. Think of how you can combine two arbitrary Sales objects before you try to implement it.
Regards, Holger
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29073993.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- View this message in context: http://old.nabble.com/Getting-started-tp29046956p29077121.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Jul 5, 2010, at 7:50 AM, Mrwibbly wrote:
This adds the data to an empty database but I can't seem to call newRecord again and add another record to the existing database.
The issue is that you need to use the new database returned by newRecord in subsequent executions of your main loop. I've coded a simpler data example showing how to do this:
-- -- Pure, Functional Data Set -- type Name = String type DB = [Name]
addName :: String -> DB -> DB addName name db = name : db
initialDB :: DB initialDB = [ "Amy", "Bob" ]
-- -- UI Actions on DBs -- addNameAction :: DB -> IO DB addNameAction db = do putStrLn "Enter name to add:" name <- getLine return $ addName name db
printNames :: DB -> IO () printNames db = mapM_ print db
-- -- Main Program -- mainLoop :: DB -> IO () mainLoop db = do putStrLn "1 = Add a name to the DB" putStrLn "2 = Print the DB" putStrLn "3 = Exit" input <- getLine case read input of 1 -> do newDB <- addNameAction db mainLoop newDB 2 -> do printNames db mainLoop db 3 -> do return ()
main :: IO () main = mainLoop initialDB
Notice how mainLoop is called recursively after the input is handled. This is how the changes to the database are propagated from one action to the next. Note: mainLoop is rather verbose, you would generally find this written as:
mainLoop :: DB -> IO () mainLoop db = do putStrLn "1 = Add a name to the DB" putStrLn "2 = Print the DB" putStrLn "3 = Exit" input <- getLine case read input of 1 -> addNameAction db >>= mainLoop 2 -> printNames db >> mainLoop db 3 -> return ()
Once you've got that under your belt, consider this version, which is even more general:
actions :: [(String, DB -> IO ())] actions = [ ("Add a name to the DB", \db -> addNameAction db >>= mainLoop), ("Print the DB", \db -> printNames db >> mainLoop db), ("Exit", \db -> return ()) ]
mainLoop :: DB -> IO () mainLoop db = do mapM_ print $ zip [1..] $ map fst actions input <- getLine let action = snd $ actions !! (read input - 1) action db
- Mark Mark Lentczner http://www.ozonehouse.com/mark/ IRC: mtnviewmark

If you have not read it yet give http://learnyouahaskell.com a look. Towards the end he walks through some of these kind of design issues starting with types and functions working on the types. Also, try putting the types and functions in a file and then loading the file in ghci with "ghci foo.hs". Now you can play with the functions by hand. This kind of experimentation is very valuable. Finally, learn about unit testing. Haskell has very solid support for test driven development and it is a good habit to get into. You start thinking "hmm this function should take XX and return YY unless ZZ is true" so you can write test cases to prove the function actually does what you think. Forcing yourself to use your own API makes you think more about how others might use it. It can also help lead you down the design path as it becomes obvious that you need say a hash to store some values.
participants (5)
-
aditya siram
-
Holger Siegel
-
Mark Lentczner
-
Mrwibbly
-
Sean Perry