Send Beginners mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."


Today's Topics:

   1.  movie database (Payan Peshraw)
   2. Re:  movie database (Daniel Fischer)
   3. Re:  [Fwd: Binary tree algorithm] (legajid)
   4. Re:  [Fwd: Binary tree algorithm] (Scott Kidder)
   5.  lazy IO in readFile (Andrew Sackville-West)


----------------------------------------------------------------------

Message: 1
Date: Fri, 7 May 2010 16:55:57 +0000
From: Payan Peshraw <[email protected]>
Subject: [Haskell-beginners] movie database
To: <[email protected]>
Message-ID: <[email protected]>
Content-Type: text/plain; charset="iso-8859-1"


Hi, 

 

I have got a database with movies added into it. What Im basically coding is:

 

- add a new film to the database
- display all the films
- display all the films by a given director
- display a list of user ratings (together with the users' names) for a given 
film
- show the average overall rating for a given director
- allow a given user to rate (or re-rate) a film (note that only the latest 
rating from the user should remain recorded)
- display all the films from a given year, sorted in descending order of 
overall rating
 
Now I want to allow a given user to rate or be able to re-rate a film. But the 
latest rating from the user should remain recorder tho..and also I want to 
display all the films that a given user likes (i.e. the films to which she has 
given a positive-valued rating). I have written the code for the user liking 
the film but it doesn't seem to work and i'm not sure what to do with that one 
eiher.
 
Below is the coding that I've written so far, but i'm stuck on the last bit 
which I can't seem to code. 
 
 
type Director = String
type Title = String
type Year = Int
type Mark = Int
type Rating = (String, Int)

type Film = (Title, Director, Year, [Rating])
type Database = [Film]

testDatabase :: Database
testDatabase = [("Casino Royale", "Martin Campbell", 2006, 
[("Garry",-8),("Dave", 0)]), 
                ("Blade Runner", "Ridley Scott", 1982, [("Amy",5)]), 
    ("The Fly", "David Cronenberg", 1986, [("Fred",7)])
    ]

addFilm :: Database -> Title -> Director -> Year -> Database
addFilm  database title director year 
         = (title, director, year, []): database
 
displayFilms :: Database ->[(Title, Director, Year, Mark)]
displayFilms [] = []
displayFilms ((i, j, k, l):xs)
               |l == [] = (i, j, k, 0) : displayFilms xs
               |otherwise = (i, j, k, overallRating l) : displayFilms xs
 
overallRating :: [Rating] -> Int
overallRating rating = div (sum [j | (_,j) <- rating]) (length rating) 
 
filmsByDirector :: Database -> Director -> Database
filmsByDirector [] filmDirector = []
filmsByDirector((i, j, k, l):xs) filmDirector
                 |j == filmDirector = (i, j, k, l) : filmsByDirector xs 
filmDirector
                 |otherwise = filmsByDirector xs filmDirector
 
filmRating :: Database -> Title -> [Rating]
filmRating [] filmRat = []
filmRating ((i,j, k, l):xs) filmRat
                |i == filmRat = (l ++ filmRating xs filmRat)
                |otherwise = filmRating xs filmRat
 
 
THIS DOESNT SEEM TO WORK?
{-
filmsLiked :: Database -> String -> Database
filmsLiked [] user = []
filmsLiked ((i,j,k,l):xs) user
                 | == user = i ++ filmsLiked xs user
                 |otherwise = filmsLiked xs user
 
person :: [Rating] -> String -> Bool
person [] userName = False
person ((n, s):xs) userName
                    |n == userName && s > 0 = True
                    |otherwise = person xs userName
-}
 
averageDirector :: Database -> Director -> Int
averageDirector [] directorRating = 0
averageDirector ((i,j,k,l):xs) directorRating
                    |j == directorRating = (overallRating l) + (averageDirector 
xs directorRating)
                    |otherwise = averageDirector xs directorRating
 
filmFromYear :: Database -> Year -> Database
filmFromYear [] filmYear = []
filmFromYear ((i,j,k,l):xs) filmYear
                    |k == filmYear = (i,j,k,l) : filmFromYear xs filmYear
                    |otherwise = filmFromYear xs filmYear
 
rateFilm :: [Rating] -> Rating -> [Rating]
rateFilm [] rating = rating:[] 
rateFilm ((user, rating):xs) (newUser, newRating)
                    |newUser == user = ((newUser, newRating):xs)
                    |otherwise = (user, rating) : (rateFilm xs (newUser, 
newRating))
 
Stuck on this bit..
{- 
changeFilm :: Database -> Title -> [Rating] -> Database
changeFilm .........
-}
 
 
 
Any help is appreciated..thank you!
                                          
_________________________________________________________________
http://clk.atdmt.com/UKM/go/195013117/direct/01/
We want to hear all your funny, exciting and crazy Hotmail stories. Tell us now
-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
http://www.haskell.org/pipermail/beginners/attachments/20100507/ea0d02fe/attachment-0001.html

------------------------------

Message: 2
Date: Fri, 7 May 2010 19:55:35 +0200
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] movie database
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain;  charset="utf-8"

On Friday 07 May 2010 18:55:57, Payan Peshraw wrote:
> Hi,
>
>
>
> I have got a database with movies added into it. What Im basically
> coding is:
>
>
>
> - add a new film to the database
> - display all the films
> - display all the films by a given director
> - display a list of user ratings (together with the users' names) for a
> given film - show the average overall rating for a given director
> - allow a given user to rate (or re-rate) a film (note that only the
> latest rating from the user should remain recorded) - display all the
> films from a given year, sorted in descending order of overall rating
>
> Now I want to allow a given user to rate or be able to re-rate a film.
> But the latest rating from the user should remain recorder tho..and also
> I want to display all the films that a given user likes (i.e. the films
> to which she has given a positive-valued rating). I have written the
> code for the user liking the film but it doesn't seem to work and i'm
> not sure what to do with that one eiher.
>
> Below is the coding that I've written so far, but i'm stuck on the last
> bit which I can't seem to code.
>
>
> type Director = String
> type Title = String
> type Year = Int
> type Mark = Int
> type Rating = (String, Int)
>
> type Film = (Title, Director, Year, [Rating])

Consider making Film an ADT,

data Film
    = Film
    { title :: Title
    , director :: Director
    , year :: Year
    , ratings :: [Rating]
    }

, maybe also Rating:

type User = String

data Rating
    = Rating
    { user :: User
    , rating :: Mark
    }

> type Database = [Film]
>
> testDatabase :: Database
> testDatabase = [("Casino Royale", "Martin Campbell", 2006,
> [("Garry",-8),("Dave", 0)]), ("Blade Runner", "Ridley Scott", 1982,
> [("Amy",5)]), ("The Fly", "David Cronenberg", 1986, [("Fred",7)])
>     ]
>
> addFilm :: Database -> Title -> Director -> Year -> Database
> addFilm  database title director year
>          = (title, director, year, []): database
>
> displayFilms :: Database ->[(Title, Director, Year, Mark)]
> displayFilms [] = []
> displayFilms ((i, j, k, l):xs)
>
>                |l == [] = (i, j, k, 0) : displayFilms xs
>                |otherwise = (i, j, k, overallRating l) : displayFilms xs
>
> overallRating :: [Rating] -> Int
> overallRating rating = div (sum [j | (_,j) <- rating]) (length rating)

That gives an error for an empty list.

>
> filmsByDirector :: Database -> Director -> Database
> filmsByDirector [] filmDirector = []
> filmsByDirector((i, j, k, l):xs) filmDirector
>
>                  |j == filmDirector = (i, j, k, l) : filmsByDirector xs
>                  | filmDirector otherwise = filmsByDirector xs
>                  | filmDirector
>
> filmRating :: Database -> Title -> [Rating]
> filmRating [] filmRat = []
> filmRating ((i,j, k, l):xs) filmRat
>
>                 |i == filmRat = (l ++ filmRating xs filmRat)
>                 |otherwise = filmRating xs filmRat
>
> THIS DOESNT SEEM TO WORK?
> {-
> filmsLiked :: Database -> String -> Database
> filmsLiked [] user = []
> filmsLiked ((i,j,k,l):xs) user
>
>                  | == user = i ++ filmsLiked xs user

That should of course be "i : filmsLiked xs user" if the function should 
return the list of titles of the films the user likes,
"(i,j,k,l) : filmsLiked xs user" if it should return a Database (as the 
type signature says in accordance with the behaviour of filmsByDirector).

>                  |otherwise = filmsLiked xs user
>
> person :: [Rating] -> String -> Bool
> person [] userName = False
> person ((n, s):xs) userName
>
>                     |n == userName && s > 0 = True
>                     |otherwise = person xs userName
>
> -}

You have the function which tells you whether a user liked a film (more 
precisely, whether a list of Ratings contains a positive rating from a 
user). The name of that function is very inappropriate, though.

Use that to write

likes :: User -> Film -> Bool
likes user (t,d,y,rs) = ???

And then use that in filmsLiked,

filmsLiked :: Database -> User -> Database
filmsLiked (film : rest) user
    | user `likes` film = ???
    | otherwise = filmsLiked rest user
filmsLiked [] _ = []

>
> averageDirector :: Database -> Director -> Int
> averageDirector [] directorRating = 0
> averageDirector ((i,j,k,l):xs) directorRating
>
>                     |j == directorRating = (overallRating l) +
>                     | (averageDirector xs directorRating) otherwise =
>                     | averageDirector xs directorRating
>
> filmFromYear :: Database -> Year -> Database
> filmFromYear [] filmYear = []
> filmFromYear ((i,j,k,l):xs) filmYear
>
>                     |k == filmYear = (i,j,k,l) : filmFromYear xs
>                     | filmYear otherwise = filmFromYear xs filmYear
>
> rateFilm :: [Rating] -> Rating -> [Rating]
> rateFilm [] rating = rating:[]
> rateFilm ((user, rating):xs) (newUser, newRating)
>
>                     |newUser == user = ((newUser, newRating):xs)
>                     |otherwise = (user, rating) : (rateFilm xs (newUser,
>                     | newRating))
>
> Stuck on this bit..
> {-
> changeFilm :: Database -> Title -> [Rating] -> Database
> changeFilm .........
> -}

What is that supposed to do?

>
>
>
> Any help is appreciated..thank you!

Generally,

- the use of i, j, k, l as parameter names is bad. If you want to use one-
letter parameters, pick the initials of their meaning, (t, d, y, r) is in 
this context much better. (title, director, year, ratings) still better.

- the argument order of your functions is irritating. It would be more 
natural to have the Database as the last argument.

- the code could be much improved by
  * using as-patterns, e.g.
    filmsByDirector (film@(_,d,_,_) : rest) dir
        | d == dir = film : filmsByDirector rest dir
        | otherwise = filmsByDirector rest dir
  * using functions like filter, e.g.
    filmsByDirector db dir = filter (dir `isDirector`) db
        where
         isDirector name (_,d,_,_) = name == d
  * using list-comprehensions, e.g.
    filmsByDirector db dir = [film | film@(_,d,_,_) <- db, dir == d]



------------------------------

Message: 3
Date: Fri, 07 May 2010 22:12:10 +0200
From: legajid <[email protected]>
Subject: Re: [Haskell-beginners] [Fwd: Binary tree algorithm]
To: David Virebayre <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=UTF-8; format=flowed

Hi,
much more simple and efficient than my solution.
I just see a strange thing. I changed < to <=, then > to >= in order to 
insert duplicate values, and added a top level function to give a list 
of values to insert.
with <=, inser [40,40,30,40,50] gives R 40 (R 40 (R 30 N (R 40 N N)) N) 
(R 50 N N)
with >=, inser [40,40,30,40,50] gives R 40 (R 30 N N) (R 40 N (R 40 N (R 
50 N N)))

Traversing the tree in ascending order from left to right, the  results 
are the same.
In the first case, left tree has a depth of three. In the second case, 
right tree does.
But are these different layouts totally equivalent?
I think that the depth of each branch is dependent upon the order of 
input data and the test (<=, >=). Can i evaluate this prior to loading 
the tree, so that i avoid having a tree with a branch much larger than 
the other one ?

Thanks,
Didier



David Virebayre a écrit :
> On Thu, May 6, 2010 at 9:51 PM, legajid <[email protected]> wrote:
>   
>> Oops, mistake in sender name.
>>
>> Hi,
>> i wanted to write an algorithm for loading a binary tree, then get the
>> values in order and other operations.
>>
>> So, i created a data type :
>> data AR a = R a (AR a) (AR a) | N   deriving (Show, Ord, Eq)
>> for an example : R 30 (R 10 (N) (R 20 N N )) (R 40 (N) (R 50 N N ))
>>
>> the main problem i had is : how to update such a complex value, to add
>> another one.
>> After hours of trying (and error !) my solution is : find where to insert
>> the new value, then read the whole tree and copy its values, except for the
>> one for insert.
>>     
>
>
> Let's say your tree is either empty or is a node that holds a value
> and two subtrees, one for values that are smaller and one for values
> that are greater.
>
> What if you want to insert a value into an empty tree ?
> You make a node with the given value and the two subtrees empty
>
> ins v N = R v N N
>
> what is the tree isn't empty ? two possibilities:
>  - the value to insert is smaller than the node's value
>    -> replace the subtree of smaller values by the result of
>       inserting the value into that subtree
>  - it's bigger
>
> ins v (R v' s1 s2)
>   | v < v' = R v' (ins v s1) s2
>   | v > v' = R v' s1 (ins v s2)
>
> question : what to do if v == v' ? I leave the question to you :)
>
> That's it :)
>
>   


------------------------------

Message: 4
Date: Fri, 07 May 2010 16:57:27 -0500
From: Scott Kidder <[email protected]>
Subject: Re: [Haskell-beginners] [Fwd: Binary tree algorithm]
To: beginners <[email protected]>
Message-ID: <1273269292-sup-1...@archlinux>
Content-Type: text/plain; charset=UTF-8

Have a look at AVL Trees or Red-black trees. They are both types of self
balancing trees which is what I think you're looking for.
-- 
- Scott Kidder
()  ascii ribbon campaign - against html e-mail 
/\  www.asciiribbon.org   - against proprietary attachments


------------------------------

Message: 5
Date: Fri, 7 May 2010 19:47:14 -0700
From: Andrew Sackville-West <[email protected]>
Subject: [Haskell-beginners] lazy IO in readFile
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="us-ascii"

I'm trying to suss out the best (heh, maybe most idiomatic?) way to
handle laziness in a particular file operation. I'm reading a file
which contains a list of rss feed items that have been seen
previously. I use this list to eliminate feed items I've seen before
and thus filter a list of new items. (it's a program to email me feed
items from a couple of low frequency feeds).

So, the way I do this is to open the history file with readFile, read
it into a list and then use that as a parameter to a filter
function. Instead of getting confusing, here is some simple code that
gets at the nut of the problem:

import Control.Monad

isNewItem :: [String] -> String -> Bool
isNewItem [] = \_ -> True
isNewItem ts = \x -> not (any (== x) ts)

filterItems :: [String] -> [String] -> [String]
filterItems old is = filter (isNewItem old) is

getOldData :: IO [String]
getOldData = catch (liftM lines $ readFile "testfile") (\_ -> return [])

main = do
  let testData = ["a", "b", "c", "d"] :: [String]
  currItems <- getOldData 
  let newItems = filterItems currItems $ testData

  print newItems -- this is important, it mimics another IO action I'm
                 --  doing in the real code...

  appendFile "testfile" . unlines $ newItems



Please ignore, for the moment, whatever *other* problems (idiomatic or
just idiotic) that may exist above and focus on the IO problem. 

This code works fine *if* the file "testfile" has in it some subset of the
testData list. If it has the complete set, it fails with a "resource
busy" exception. 

Okay, I can more or less understand what's going on here. Each letter
in the testData list gets compared to the contents of the file, but
because they are *all* found, the readFile call never has to try and
fail to read the last line of the file. Thus the file handle is kept
open lazily waiting around not having reached EOF.  Fair enough. 

But what is the best solution? One obvious one, and the one I'm using
now, is to move the appendFile call into a function with guards to
prevent trying to append an empty list to the end of the file. This
solves the problem not by forcing the read on EOF, but by not
bothering to open the file for appending:

writeHistory [] = return ()
writeHistory ni = appendFile "testfile" . unlines $ ni

And this makes some sense. It's silly to try to write nothing to a
file.

But it also rubs me the wrong way. It's not solving the problem
directly -- closing that file handle. So there's my question, how can
I close that thing? Is there some way to force it? Do I need to rework
the reading to read one line ahead of whatever I'm testing against
(thereby forcing the read of EOF and closing the file)? 

thanks 

A

-- 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
Url : 
http://www.haskell.org/pipermail/beginners/attachments/20100507/da9e1c97/attachment.bin

------------------------------

_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners


End of Beginners Digest, Vol 23, Issue 8
****************************************

Reply via email to