I've always been interested in other programming languages, and have dabbled in many, although I am only versed in C++ and Pascal (even my Pascal is getting rusty). One of the best things about Artificial Intelligence is that its broad range of applications and areas of research allow many programming languages to be utilized in some form or another. This essay will focus a few interesting programming languages that I have looked at, and how they can be used in Artificial Intelligence. Each section has a brief overview of how you can get started in that programming language, and then why you might want to use the language. Below is a list of the languages covered or to be covered.
8000 factorial size [Ctrl+D pressed now] 2882To digress, this example also demonstrates SmallTalk's almost unlimited precision with numbers. If you have a 200Mhz+ computer, try evaluating the factorial of 8000. The number SmallTalk outputs is 8 A4 pages long! All of this though is merely scratching the surface of SmallTalk - the most interesting aspect of the language is that everything is an object. I always thought that C++ was very object-orientated (and indeed it is in its own right), but it is nothing compared to SmallTalk! For example, in C++ basic types (like integers, floating point numbers, boolean values and characters) are not objects, whereas SmallTalk they are. All objects in SmallTalk communicate via messages.
Messages 8 - 23 -15 4 / 3 4/3 4 / 3 asFloat 1.33333333 3 squared - 4 5 4 + 2 * 3 18 3 ** 8 6561There are few important things to note in the above code fragments. For example, notice how SmallTalk preserves accuracy by expressing all numbers as fractions. To force a floating point result, use the asFloat message. Another thing to note is the order precedence is not supported. Look in the example #5, "4 + 2 * 3" evaluates to 18, not 10. This is obviously rectified through use of parenthesis: 4 + (2 * 3) 10A final thing to note is that ** stands for power - therefore, the last example is 38.
Readability 'The brown quick fox' replaceFrom: 5 to: 15Most programmers will be initially confused because (unlike most programming languages), SmallTalk is based on 1-index, not 0-index. This makes SmallTalk even more readable! Of course, a large portion of the readability simply comes from the names that are given to the messages. SmallTalk is not always perfectly readable, for example an if-statement looks something like this: (boolean statement) ifTrue: [do something]Nevertheless, the power that comes from the messaging far overpowers the reading quirks it produces! With this basic overview, why would we use SmallTalk?
Why SmallTalk? SmallTalk is often cited as an excellent language for natural language processing applications, but this can be extended to advanced data manipulation (which NLP essentially reduces too). This is due to the un-typed nature of SmallTalk: a := 4. b := 'hello'. b := a. b 4Four is assigned to a (which is not declared prior to this statement), and the literal string 'hello' is assigned to b. Now, a is assigned to b. Finally, the value of b is evaluated as 4 even though it was assigned a string value at first. Try doing something like that in C! It is also excellent with lists/arrays which NLP relies heavily on: #(1 2 3) at: 2 put: 'Hello'; yourself #(1 'Hello' 3)Another example of the un-typed nature of SmallTalk coupled with its excellent list capabilities. Dolphin SmallTalk is aimed at creating Windows applications, and provides a very well designed interface for adding new classes and methods. Dolphin SmallTalk can be found at Object-Arts.com.
Like the SmallTalk environment, Forth is interactive. In Forth, though, expressions do not have to be evaluated, this is done automatically when you enter a carriage return. For example, try typing in these statements in the Forth environment (red is what the Forth system will output): 1 . 1 ok 2 . 2 ok do you know what this is? Error: do compilation only what about this? Error: what is undefinedForth programming revolves around a pair of stacks and a dictionary of words. One of the stacks is a data stack, a structure most computer programmers will be only too familiar with (especially those of us that have done any assembly work!). The dictionary of words is a huge (for Win32Forth, 4231 words are in the standard dictionary) collection of words that can be used in any Forth program. If during the course of your program creation you need new functions (or words, to keep with Forth lingo) you must add to that initial dictionary. For example, note what happens to the total number of words when I add a plustwo function: : plustwo ( n -- n+2 ) 2 + ; ok vocs [Removed vocs intermediate output] ----------------------------------------- Total System Words: 4232It increased by one! So, since simplicity is key when programming in Forth, you set about programming using "just" this set of words and the stack (don't worry about the other stacks for the minute). Let us have brief look at the data stack in Forth.
Data Stack .s empty ok 10 20 30 40 50 ok..... .s [5] 10 20 30 40 50 ok..... drop drop ok... .s [3] 10 20 30 ok...Arithmetic in Forth is done using postfix notation, as opposed to infix used in SmallTalk. Postfix has the added advantage of not requiring order precedence rules, since there is only one way to interpret an expression. In postfix notation, all operators come AFTER both the numbers they require. For example, "2 + 3 * 4 - 3" in infix notation translates into "2 3 4 * + 3 -" in postfix notation. Try entering in the postfix expression in Forth followed by a period (".") which instructs Forth to output the result (11). Now, why has this all been listed under the data stack section? Math operators will take the first two numbers off the stack and use them instead of having them explictly specified. Look at this: 2 .s 3 .s 4 .s * .s + .s 3 .s - .s [1] 2 [2] 2 3 [3] 2 3 4 [2] 2 12 [1] 14 [2] 14 3 [1] 11 ok.I've formatted the output to make it easier to see what happens. Firstly, 2, 3 and 4 are pushed on to the stack. The * operator then takes 3 and 4, multiples them and pushes the result on to the stack (12). The + takes the 2 and 12, adds them and pushes it on to the stack. The 3 is pushed on, and subsequently removed with the 14 and subtracted and pushed on to the stack for a final result of 11. Now that we've looked at the basics and the data stack, lets see how we can expand on the programs functionality by adding new words.
Adding Words I will return to the plustwo example before. Adding a definition involves the word, a stack-effect comment and the word code. The stack-effect comment is simple a comment that tells the user (programmer) what the word does, it has no effect on the code itself. So, back to our plustwo definition: : plustwo ( n -- n+2 ) 2 + ;plustwo is the word, the "( n -- n+2 )" is the stack-effect comment. It can be anything you want, but I follow the convention that Leo Wong's Forth Tutorial uses (see end of essay). The next part is the code itself, followed by a semi-colon. You will note how the stack it used in this case - a number is pushed on to the stack, then the function pushes a 2 on, and adds them both.
Why Forth? "...Forth is, among other things, a programming language whose ideals are freedom and simplicity. Freedom requires knowledge and responsibility, and simplicity is yet more demanding. But "simple" can also mean rudimentary..."This is another rather appealing aspect of Forth. Forth is also a great intermediate step between higher-level languages and assembly language. It is also a nice bridge if you already program both (as I do). Forth enables you to think at an assembly level with the convience of various higher-level concepts. This is probably due to the fact that Forth was designed for machinery (originally for telescopes, but later for robotics in general). There are many areas of Forth I have not covered here including variables, direct memory access and many other things Forth is capable of. Check out Forth.org for more information on Forth, including a link to download Win32Forth.
The best way to see Prolog is action is to look at an example program. This is a simple program I created after an hour going through documentation: PREDICATES nondeterm person(symbol) nondeterm guitar(symbol) nondeterm likes(symbol, symbol) nondeterm wants(symbol, symbol) nondeterm present(symbol, symbol)Predicates get their name from predicate logic - the logic that Prolog uses to infer. CLAUSES
person("James").
person("Gemma").
wants("Gemma", "Ibanez Jem7").
wants("James", "Ibanez UV777BK").
guitar("Ibanez Jem7").
guitar("Ibanez UV777BK").
These are simple clauses - the ones here are simple facts. For example, the first statement simply means "James is a person", the 3rd one means that "Gemma wants an Ibanez Jem7" and the 5th one means "An Ibanez Jem7 is a guitar". Notice how every line ends with a period, much like natural language.
likes("James", Something):- guitar(Something).
likes("James", "Gemma").
This is a bit more complicated - this is called a rule since it has a dependency. This specifies that "James likes SOMETHING if that SOMETHING is a guitar. James also likes Gemma." In Prolog, anything that is a literal string (surrounded by quotation marks) or starts with a lowercase is considered a constant. Anything with a capital letter is considered a variable. The use of "Something" merely makes reading the statement easier, and does not make a difference to the Prolog engine. The ':-' is read IF.
likes("Gemma", Something):- likes("James", Something).
likes("Gemma", "James").
This rule reads "Gemma likes SOMETHING if James likes SOMETHING. Gemma also likes James." - so you can see how the rules in Prolog can be embedded and interlinked. If you had a huge database of such rules, you can imagine how powerful the inference engine could be.
present(Name, Model):-
person(Name),
likes(Name, Model),
wants(Name, Model).
This is a more complicated rule that uses multiple clauses to figure out whether MODEL is a good present for NAME. The rule states "MODEL is a good present for NAME if NAME is a person, NAME likes MODEL and NAME wants MODEL."
GOAL
% present("James", "Ibanez UV777BK").
% present("James", What).
% guitar(What).
% wants(Who, "Ibanez Jem7").
% likes("Gemma", Who).
% present("Gemma", "Ibanez UV777BK").
The GOAL section allows the user to specify one goal for the inference engine to find. The goals can be in the form of a yes/no question, or a general query. I created 6 goals that can be uncommented (Prolog uses % to comment a line). If any of you have access to a Prolog compiler, you can download this 'program' here.
Why Prolog? I've got to admit I wasn't as impressed with Prolog as I've been with the other programming languages. I attribute this, though, to me being a 'procedural' programmer and my lack of experience with the language! I like to have control over what the program is doing, and not letting something do all the work "behind the scenes." Nevertheless, what Prolog does it does very well. Visual Prolog came with some excellent documentation, so I'm sure I'll come to like the language more once I can actually do something with it!
|