7 Replies - 2933 Views - Last Post: 12 December 2011 - 09:39 AM

#1 Paticia  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 01-December 11

[Haskell] Improving my assignment answer.

Posted 10 December 2011 - 08:20 PM

Hi all!
Finally I’ve finish my assignment. All my functions are working! \o/
Now I’m trying to improve my code (btw, I’m sure that my code sucks… but I’m still learning :P )
And I really need/want to have a good grade on this assignment. So, any little help would be appreciated.

So, the story, once again, is like this: there's a chain of restaurants. Each restaurant is a 3-tuple with a “restaurant name”, an number of tables and a 3-tuple list with the menu (price, "recipe name" , "special ingredient") :

("restaurant name", number of tables, [(price, "recipe name" , "special ingredient")])


The fowling list is given:

chainRestaurants = [("Food and friends",20,[(2.5,"Steak","lemon"),(3.5,"Vegetarian Meals","tomato"),(4.0,"Italian Beef","banana")]),("All in",10,[(2.5,"Stracotto","Garlic"),(3.0,"Roast Beef","Butter"),(3.3,"Veal Chops","Pepper")])]


What I have to do is to edit the “restaurant name” and the "number of tables"

I was able to make (whit the help of dreamincode community _o_ ) 3 different codes for this question:

CODE 1.

chainRestaurants = [("Food and friends",20,[(2.5,"Steak","lemon"),(3.5,"Vegetarian Meals","tomato"),(4.0,"Italian Beef","banana")]),("All in",10,[(2.5,"Stracotto","Garlic"),(3.0,"Roast Beef","Butter"),(3.3,"Veal Chops","Pepper")])]

menu1 = [(2.5,"Steak","lemon"),(3.5,"Vegetarian Meals","tomato"),(4.0,"Italian Beef","banana")]
restaurant1 = ("Food and friends",20,menu1)

menu2 = [(2.5,"Stracotto","Garlic"),(3.0,"Roast Beef","Butter"),(3.3,"Veal Chops","Pepper")]
restaurant2 = ("All in",10,menu2)

chainRestaurants1 = [restaurant1] ++ [restaurant2]

editinfo3 1 newRestaurant_name newtableinfo = [(newRestaurant_name,newtableinfo,menu1)] ++ [restaurant2]
editinfo3 2 newRestaurant_name newtableinfo = [restaurant1] ++ [(newRestaurant_name,newtableinfo,menu2)]
editinfo3 _ newRestaurant_name newtableinfo = error "No such thing"



CODE 2.
chainRest1 [(_,_,[(c,d,e),(f,g,h),(i,j,k)]),(l,m,[(n,o,p),(q,r,s),(t,u,v)])] newRestaurant_name newtableinfo = [(newRestaurant_name,newtableinfo,[(c,d,e),(f,g,h),(i,j,k)]),(l,m,[(n,o,p),(q,r,s),(t,u,v)])]
chainRest2 [(a,b,[(c,d,e),(f,g,h),(i,j,k)]),(_,_,[(n,o,p),(q,r,s),(t,u,v)])] newRestaurant_name newtableinfo = [(a,b,[(c,d,e),(f,g,h),(i,j,k)]),(newRestaurant_name,newtableinfo,[(n,o,p),(q,r,s),(t,u,v)])]

editinfo2 1 newRestaurant_name newtableinfo = chainRest1 chainRestaurants newRestaurant_name newtableinfo
editinfo2 2 newRestaurant_name newtableinfo = chainRest2 chainRestaurants newRestaurant_name newtableinfo
editinfo2 _ newRestaurant_name newtableinfo = error "No such thing"




CODE 3.

editinfo1 1 newRestaurant_name newtableinfo = aux newRestaurant_name newtableinfo chainRestaurants
                               where aux a b ((_,_,c):dds) = (a,b,c):dds                                        
editinfo1 2 newRestaurant_name newtableinfo = aux newRestaurant_name newtableinfo chainRestaurants
                               where aux x y ((a,b,c):(/>_,_,z):ds) = (a,b,c):(x,y,z):ds
editinfo1 _ newRestaurant_name newtableinfo = error "No such thing"




So, now I have 2 questions:
1. Which of those 3 answers have a "better" code?
2. Imagine that, instead of 2 restaurants, I have a chain of 100 restaurants. For any of my answers, it will give me a bunch of code lines, which make me thinking: there's should be another way to solve this, to prevent 100 or 200 lines of code for a case of 200 restaurants. Any ideas for a... more "pragmatic" way to solve this problem?

Ty all!!

Is This A Good Question/Topic? 0
  • +

Replies To: [Haskell] Improving my assignment answer.

#2 ishkabible  Icon User is offline

  • spelling expret
  • member icon




Reputation: 1622
  • View blog
  • Posts: 5,709
  • Joined: 03-August 09

Re: [Haskell] Improving my assignment answer.

Posted 10 December 2011 - 09:18 PM

well im no expert in Haskell but i can offer a few things i see.

1) "code 2" is horrible, it makes my eyes bleed. if you ever find your self writing a pattern that long and complex your doing it wrong.

im not curtain what "editinfo3" is supposed to do but it seems like it uses global in a strange way. "editinfo1" actually appears to be useful and doesn't have any strange behavior.

2) i would store the information in a file and load it at run-time for the rest of the code to use

something like...
main = do
    restaurantData <- loadRestaurantData
    preformOperationsOnData restaurantData



also, creating your own type for this would be much better than using tuples. for instance, you might have a type "Dish"

data Dish = Dish Int String String


and then you might have another type "Restaurant"

data Restaurant = Restaurant String Int [Dish]

This post has been edited by ishkabible: 10 December 2011 - 09:20 PM

Was This Post Helpful? 1
  • +
  • -

#3 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2101
  • View blog
  • Posts: 3,204
  • Joined: 21-June 11

Re: [Haskell] Improving my assignment answer.

Posted 11 December 2011 - 07:45 AM

chainRest1 [(_,_,[(c,d,e),(f,g,h),(i,j,k)]),(l,m,[(n,o,p),(q,r,s),(t,u,v)])] newRestaurant_name newtableinfo = 


The biggest problem with this code (aside from its readability) is that you're hard coding the lengths of the lists. If you call it with an outer list of more or less than two elements, it will fail. If those elements contain inner lists of more or less than three elements, it will fail.

You should rewrite that function so it can handle lists of any length.
Was This Post Helpful? 1
  • +
  • -

#4 Paticia  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 01-December 11

Re: [Haskell] Improving my assignment answer.

Posted 11 December 2011 - 07:45 AM

@ishkabible
ty for yours suggestions.

About "code 2" ... I've only tried it because... well, more for study. with a small list, it could be nice, but I really agree: this code also make my "eyes bleed".

The "code 3" was initially something like:
foo x y ((_,_,z):xxs) = (x,y,z):xxs

but i didnt wanna pass a list as argument. So, I create an aux function.


About the use of tuples, unfortunately it's an assignment requirement. :/

All the other ideas... I'll add them!!

Thank you very much!
Was This Post Helpful? 0
  • +
  • -

#5 Paticia  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 01-December 11

Re: [Haskell] Improving my assignment answer.

Posted 11 December 2011 - 08:06 AM

View Postsepp2k, on 11 December 2011 - 07:45 AM, said:

You should rewrite that function so it can handle lists of any length.


That is my biggest problem, since the beginning. My codes works fine for smaller lists (like my 2 or 3 restaurants)... but if I have a longer list (like 100 or 200 restaurants)? :/

From your response, I assume that there's a way to "handle lists of any length". Am I far away from achieve it?

ty.
Was This Post Helpful? 0
  • +
  • -

#6 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2101
  • View blog
  • Posts: 3,204
  • Joined: 21-June 11

Re: [Haskell] Improving my assignment answer.

Posted 11 December 2011 - 08:24 AM

There are two ways to pattern match on lists: The first is to use a pattern of the form [foo, bar, baz]. This is what you're using. This only works for lists of a fixed size.

The other form, which you should be using to handle lists of any size, is to match on the list constructors. There are two constructors for lists: [], which is the empty list. And x : xs, which is the non-empty list whose first element is x and whose other elements are stored in the list xs.

Since you used the third way in your code 3, I assume that you already know how to use it in principle. But since you still seem to have some trouble, here's a somewhat general explanation of how to use it nonetheless:


When you write a function to handle lists of any size, it usually looks something like this:

foo [] = valueForAnEmptyList
foo (x:xs) = combine (valueForASingleElement x) (foo xs)



I.e. you're doing one thing if the list is empty, and if it isn't you do something to the first element of the list and then do the same thing to all other elements in the list and then you combine the results somehow.

As a more concrete example that is somewhat similar to what you want to do. Imagine a function that should take a list of 3-tuples as its first parameter, a number n as its second parameter and a value y as its third parameter. It should return a new list which is the same as the original list except that the middle value of the nth tuple has been replaced with y. That function would look like this:

foo [] _ _ = error "List does not have enough elements"
foo ((x1, x2, x3):xs) 0 y = (x1, y, x3) : xs
foo (x:xs) n y = x : (foo xs (n-1) y)



I.e. if n is 0, you take the first tuple of the list, separate it into its parts, create a new tuple where the middle part has been replaced with y and put that tuple in front of the list's tail. If n is greater than 0, you leave the tuple unaltered, but you call the function recursively to alter the (n-1)st element of the tail.

This post has been edited by sepp2k: 11 December 2011 - 08:27 AM

Was This Post Helpful? 2
  • +
  • -

#7 Paticia  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 01-December 11

Re: [Haskell] Improving my assignment answer.

Posted 11 December 2011 - 10:08 PM

well sepp2k, let me just say that if you're not a teacher... you should considerate that!
Thanks you very much!

But now... you just made me review my full assignment! lol

So, one more question. If I have:
xs = [(11,22,[(33,33,33),(44,44,44)]),(55,66,[(77,77,77),(88,88,88)])]

Can I use constructors to pattern match the lists of tuples inside the tuples from the xs list?
I.e. can I "replace" the nth tuple from the xs list (33,33,33)or(44,44,44) or (77,77,77)or (88,88,88)? I've try to do that, but without success. :(

Based on your post, I'm now able to change the tuples of a list of tuples:
xxs = [(11,11,11),(11,11,11),(11,11,11)]
foo [] _ _ = error "List does not have enough elements"
foo ((x1):xs) 1 y = (y) : xs
foo (x:xs) n y = x : (foo xs (n-1) y)


After that I've tried I've almost everything that I can remember. I believe that my best approach was something like: foo = (x1:x2:x3:xs) n p y = x1:x2:y: xs :/

I've tried for hours... And I didnt even know if it's possible! :S
Was This Post Helpful? 0
  • +
  • -

#8 Paticia  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 01-December 11

Re: [Haskell] Improving my assignment answer.

Posted 12 December 2011 - 09:39 AM

View PostPaticia, on 11 December 2011 - 10:08 PM, said:

After that I've tried I've almost everything that I can remember. I believe that my best approach was something like:


xxs = [(11,22,[(33,33,33),(44,44,44)]),(55,66,[(77,77,77),(88,88,88)])]
foo [] _ _ _ = error "-.-/>"
foo ((x1:x2:x3):xs) 1 1 y = (x1:x2:y): xs  -- I'm sure that there is some errors
foo (xa:xb:xc:xs) n  p y = xa:xb:((foo xc (p-1) y): (xs (n-1))) --  wont compile ://>

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1