4 ms·
I tried programming in prolog and read some introductionairy books. However, no book talks about how you would define more complex 'types' objects. How would yo
by randomUser1122 9y ago
I tried programming in prolog and read some introductionairy books. However, no book talks about how you would define more complex 'types' objects. How would you model the following domain in prolog:
Comment:
Attributes: text, points
User:
Attributes: name, emailAdress(as a struct of first part, domain, top-level-domain)
Admin(a special user):
additional Attributes: set of rights(can delete, can hide, can modify)
Finally, there is an n-1 assocation between Comment and User and I want to make some queries about this domain.
- zmonx 9y agoThere are several ways to do it. One straight-forward way is as follows: We can represent comments by facts like: comment_id_user_text_points(3, 1, 'hello!', []). I do not know what exactly you mean by "points", so I have simply supplied an empty list (fourth argument) in this case. Note that there is an ID for the comment, and an ID for the user that posted the comment. Therefore, we say that this is a relation between users and comments and their text and points, usable in all directions. Each user can likewise be represented as follows, relating a unique ID to a name and e-mail address: user_id_name_email(1, 'randomUser1122', [random,'ycombinator.com']). For admins, I can simply add additional facts, relating user IDs to rights like this: admin_id_rights(1, [delete,hide]). Now, we can simply post queries over these facts, such as: ?- user_id_name_email(ID, _, _), comment_id_user_text_points(_, ID, Text, _). and obtain, on backtracking, all comments for any user. This is all completely analogous to how you would represent such data in any database system. It's more convenient in Prolog though for several reasons.
- randomUser1122 9y agoWow, modelling it like in a relational DB is a great idea! Thanks. Your trick of adding names of the properties like "_id_user_text" is neat. In the past, I tried a similar solution like but I would always forget which property is at which position. How would you make sure that the rights of admins are only delete, hide, and modify (and not e.g. walk, talk, chalk) ? If I use admin_id_rights(Id, Rights):- numeric(ID), sort(Right, SortedRights), subset(SortedRights, [delete, hide, modify]). , then I obviously have added all possible admins. Moreover, how would you then 'create' objects without adding them with asserta. Assume that all the user, admins, comments are written to a text file which should be queried. I can easily read them into some nested compounds with DCGs. However, I would like to create objects(e.g.like Java's new) to check that they adhere to the contraints of my model.
- zmonx 9y agoThe naming trick makes clear what each position means: The order of arguments follows that of the name's components. So, if the name contains id_user_text, then the arguments are also in this order: ID of comment, ID of user, and the text. This is a simple mnemonic technique I use for naming important predicates. As to your first question, we are now talking about (database) integrity constraints. So I would first state which rights are admissible at all by clearly defining what we consider a right. For example, in this concrete case: right(delete). right(hide). right(modify). Next, I describe the situation that an admin was inadvertently assigned a "bad" (i.e., not actually existing) right: user_bad_right(ID, R) :- admin_id_rights(ID, Rs), member(R, Rs), \+ right(R). Now, I can ask Prolog: Are there any bad rights assigned? I do this by simply posting the most general query about this relation: ?- user_bad_right(ID, R). false. I conclude: No, there are no bad rights assigned. As for creating objects: This is a good case of using the dynamic database, i.e., predicates like assert/1 and assertz/1. The database is very good for frequently retrieving information, but not good for frequently updating the information. This is a fitting situation: Comments are presumably only posted once, and in that case, you can simply add such facts to the database. But you can of course also make all this explicit, and first construct a term of the form comment_id_user_text_points(3, 1, 'hello!', []), and then reason about such terms (instead of reasoning about the asserted facts). Note that this term looks exactly like the fact syntactically, due to the homoiconic nature of Prolog. Therefore, you have many ways to reason about your data. You can even write all such terms to an external file, and simply consult all facts (and even rules) it contains by invoking consult/1 dynamically.
- randomUser1122 9y agoThank you for all you great tips. Do you know any good book(except Craft of Prolog, Prolog for AI) or good code on github following this principle?
- zmonx 9y agoThank you for your interest! Since Prolog is now gaining more traction, I am adding to my favourites all Prolog links which I consider noteworthy or recommended reading. Please see my profile for more information, and also for future updates.
- tom_mellior 9y agoHere's a shot. As you don't declare relations in Prolog the way you would, say, write SQL CREATE statements, I'll just show the data model on concrete data. comment("I tried programming in prolog...", 100, randomUser1122). comment("Here's a shot.", 2, tom_mellior). user(randomUser1122, email(random, randomdomain, com)). user(tom_mellior, email(tom, mellior, su)). admin_right(randomUser1122, delete). admin_right(randomUser1122, modify). Is there a user from the Soviet Union with admin rights? ?- user(User, email(_, _, su)), admin_right(User, right). false. What rights do users with posts with a score of at least 10 have? ?- comment(_, Score, User), Score >= 10, admin_right(User, Right). Score = 100, User = randomUser1122, Right = delete ; Score = 100, User = randomUser1122, Right = modify .