I absolutely love programming in Prolog. I've never needed to write anything large in it at all (which is where most prolog interpreters fail), but when it comes together so beautifully at the end, its quite amazing.
I thoroughly recommend "The Art of Prolog" which is an engaging and fun read.
When I first learned about Prolog in AI class, the first thing that struct me was how beautiful Prolog/logic programming solutions are.
In non-declarative languages like Java, you have to build up the different pieces of computations, while you keep maintaining a mental picture of how the various pieces fit together.
In Prolog, you declare the entities and the relationships/constraints between them, and the system will build the solution for you through inference.
David Nolen has done some awesome work writing the core.logic[1] library, which makes those Prolog gooodies accessible to Clojure programmers.
I seem to recall that one of the issue with Prolog is that, above a certain level of complexity, you can't really write purely declarative Prolog "progams" - you have to start considering the procedural aspect as well which (in certain cases) can be non-trivial.
You indeed have to understand how the Prolog engine works in order to structure the declarative statements of your code in a way that will lead to an efficient execution.
A way to see a Prolog programs is as a sequence of facts and statements, and at least one query. The Prolog engine will then search for a solution that fits the given facts and requirements and answer the query. In a way the Prolog engine will search a space of possible answers to the query to find the one(s) that match the given facts and requirements. The key to speed is to structure the facts and statements that the search will fail as early as possible when a wrong path is taken. This amount to pruning the useless parts of the search space as aggressively as possible, so that the Prolog engine does not waste time evaluating options that are doomed in the end.
Before getting this I was often frustrated with apparently nice and correct Prolog programs that took forever and in effect just looked stuck (at some point you just stop waiting and abort the execution). I guess it's a pretty common frustration when beginning in Prolog. But once you get it, it's possible to come up with efficient code. It's still scary to see that some small changes in statements ordering can lead to dramatic difference in runtime. You can have big differences in performance for imperative programming too, but it's rare that it's so bad that a first implementation is completely useless. In Prolog it's quite common. And the way to optimize Prolog performance is very specific, you need to learn to anticipate how the engine walks the search space. I guess it's one of the big roadblock in the practical use of Prolog.
A book -- in fact, the book -- that covers this sort of thing is Richard O'Keefe's The Craft of Prolog, which, like Sterling & Shapiro's The Art of Prolog, is put out by MIT Press.
Mercury[1], a derivative of Prolog does away with these cuts. So I guess that these declarative short-circuits in Prolog are just a fault that arose because some things were not thought through in the creation of Prolog.
At university we had to learn prolog and for me (C/perl) it was mind blowing experience. Fact that you are writing program as bunch of logical predicates was kind strange at first, but when you get used to it, it's such a great and powerful tool. Also, learning things like unification was just wooow.
So, I'd recommend prolog to every programmer, especially today when most people use yet another standard language. On the other hand prolog is sooo out of the box.
I find Prolog a marvel in "look what I can do!" Writing stupidly fun code in it is almost a no-brainer, compared to other languages (I have a half-assed English grammar parser in 60-odd lines, with a few comments!) But getting into prolog needs a complete rewire of how you think about programming: if you are used to imperative (or functional, or list-based, or almost whatever else) prolog feels very foreign.
I'm also a Lisp aficionado, having written more than a few small pieces (not counting emacs lisp, where I write more than a few!) to scrape the web or draw Lavaurs chords.
And my day-to-day I write PHP, Python, awk, R and whatever it takes to improve revenues in my company. So I have both perspectives, Lisp & Prolog and its awesomeness and "the other side." And mixing them up (splurge into data with awk, write it as Prolog terms, analyse its structure in Prolog and represent it in R) is one of the biggest joys of programming. Don't get entrenched in your "language," learn as many as you can and cherry-pick each one as you see fit for the problem.
Indeed! During a security assessment of a large code base, I wrote a simple ruby source code parser that spat out Prolog terms. After that, it was a breeze to find certain kinds of logic errors, such as code paths that used user input before sanitation...
It's beautiful when it all works together, checking everything manually would certainly have been a PITA and would have resulted in a lower quality result.
Every time I use prolog for something (or more like I think "Ha! This is meat for Prolog!") I feel like I'm just using an awesomely sharp knife. As I like to put it, it's like a database on steroids.
A few months ago I was "bored" and decided to write a "scrapper" (kind of) to get all my tweets (this was before twitter opened tweets for download). It was relatively easy: write a little javascript that scrolls to bottom and then regex-matches all the (correctly loaded now) tweet data in the webpage. Then collect the tweet text in a plain ol' list that then is dumped on-screen as prolog terms... and saved as plain text.
With this simple thing I could make interesting queries (who I mention more often, when I'm more prone to tweet...) in a breeze, and I could made even better queries with a little more work/available data.
Could you open source it? I'm very interested in seeing how one would do that, I've been thinking about writing one myself, for PHP (I've a somewhat large codebase to inherit, that only works in a old version of PHP, and I might need to migrate it).
I don't have the IP for the code so I can't copy it here, but what I did was very simple and the gist of it is described below:
The parser used regular expressions to recognise function definitions and calls in those definitions.
I used file names as the function scope, this was good enough because there were no two functions with identical names in the same file.
Function calls became the following terms: "calls(x,y,z).", meaning that function x in file y calls z.
These "calls" terms actually define a directed graph.
If you google "prolog path through directed graph", there are lots of hits that will help you out.
The following (untested) code should get you started:
%there is a path if there is a call
path(Caller, File, Called, [calls(Caller, File, Called)]) :- calls(Caller, File, Called).
%there is a path if there is a call to some function and there is a path from that function
path(Caller, File, Called, [calls(Caller, File, A) | P]) :- calls(Caller, File, A), path(A, _, Called).
After that, you can find all possible paths with "findall/3" and check for existence of a certain known good/bad function with "member/2" (again, google is your friend)
Due to some properties of the code, this simple approach worked well enough for me.
Hopefully this helps you out.
Probably needs a green cut in the first term... Or maybe not. I'm quite backtracking-puzzled about green cuts in generic terms I write, so thinking about them in others' code is even more puzzling :)
Back when I was at the university, Prolog and Lisp were the forbiden languages to write compilers on our compiler courses, because the teachers saw them as making the whole exercise too easy.
A few people have asked if the video and slides for this talk are available. Unfortunately it did not get recorded and the slides don't make much sense without the words and there was a considerable amount of live coding in a REPL.
However I'll be attending http://webrebels.org where I'll be giving a more refined version of the talk - it will be recorded.
On the subject of why amazingly-powerful, ahead-of-their-time languages don't catch on.. I'd be interested to know if a study has ever been done on the "accessibility" of a language and its popularity.
By which I mean: A total novice, even a non-programmer, can be given a simple bit of PHP/Javascript, and work out what it does and how to make minor changes to it. But something like Lisp & Haskell, you just can't do that - you need to spend some time learning the syntax before you can do anything with them.
I'd be surprised if the ramp-up time to be able to do useful things with a language didn't have more of an effect than how powerful and useful it is.
A person off the street gets the idea of a recipe. Most will get the idea of a process for taking a list of ingredients and producing a new recipe. But the idea of a procedure that takes a procedure for taking a list of ingredients and produces a recipe, and produces a new procedure for...etc. [I need some parentheses].
It's not the syntax of Lisp that is hard to learn. Nor is it the language primatives. What makes Lisp hard is the expressiveness of their idiomatic usage.
What makes Lisp difficult is how quickly one gets to abstract mental constructs like recursive definitions and procedures which take procedures as arguments - all before macros and meta-linguistics. That's saved for after lunch.
The worst part is that Lisp makes it look simple. A few micrograms can create a mind blowing experience.
But Lisp has rather less syntax than most other programming languages - and that's possibly a weakness rather than a strength when it comes to anyone new to the language.
I suspect there is a sweet spot when it comes to the syntactic complexity of programming languages - too little and people get lost in the generality and abstractions, too much and its difficult to remember it all and you end up with coding standards desperately trying to close down on the features that should be used (e.g. banning the ternary conditional operator).
> Lisp has rather less syntax than most other programming languages - and that's possibly a weakness
Yup: it's like saying that binary is easier than decimal because it has less digits - the average Joe would still find it easier to do his maths in base ten :)
Personally, I find both Lisp-1 and Lisp-2 easier to read (when it is pretty printed) than any other language syntax.
That the syntax or lack there of also expresses itself as an AST in addition to that is quite elegant.
Due to the reduction in syntax verbosity it is evident in the code what the important elements are as that is the only information displayed.
Lisp's syntax enables powerful utilities like Paredit to exploit that for unrivaled transpositions of the code as refactoring occurs.
I do think other syntax designs look more aesthetically pleasing on its face than what either Lisp-1 or Lisp-2 appear to the novice (the ML family of languages for instance) but it is something I have come to appreciate as my proficiency in Lisp has improved.
Code simultaneously being data and the converse as well is another elegant consequence of Lisp's design, so everything is optimized for the tail, which is what is important for tools and the environment to provide.
I wish the environment provided in other languages was as mature as that of Common Lisp (http://www.cliki.net/development), because it is immensely pleasurable to code in once the learning curve is overcome.
The quality of documentation and literature available for Lisp is also excellent, many of which are classics in Computer Science as a result and are worth reading regardless of actually using Lisp to develop with.
The comparison is not really valid. The point was that one has to spend "less" time to learn Lisp's syntax.
Thus, learning binary syntax vs. decimal syntax is indeed easier, as it is easier to learn Lisp's syntax when compared to other languages like, say, Java or C++.
In both cases I wouldn't say that learning the syntax is the problem. The challenge IMHO lies in the different execution models. And there starting with LISP is likely a good idea, as it's less different than Prolog. It's functional, but still imperative. While in Prolog the switch to declarative programming is more disruptive in my experience (and mind blowing / expanding).
The hard thing in Prolog is that for a non trivial program (and not even a big one) it becomes necessary to understand how the underlying engine works on your code rules in order to be efficient. I had a real case where reordering a few statements meant going from ~15mn to find the first solution to a problem to a split second for all 7 ones!
What helped me with Prolog is viewing the runtime as an engine searching through a possibilities space for a solution fulfilling the program requirements (constraints). The trick is then to layout the requirements to fail early during the search, so that the engine doesn't waste time exploring doomed parts of the space of possibilities.
This is an interesting line of inquiry. I wonder, though, what would be a good way to quantify accessibility. I find myself doubting your statement that even non-programmers would find JavaScript or PHP easier than Lisp due to syntax, given the latter's extreme simplicity of syntax. Programmers with C/Java/etc. experience would of course likely find JS and PHP more familiar and hence accessible.
This doesn't match my experience at all. People with literally no programming experience do not magically understand what a for-loop does. In fact--at least among the people I've tried teaching myself--they don't even understand what a mutable variable is! (And it's not like I used that term: I try to explain it in a simple way.) Learning the syntax for Php or JavaScript isn't that easy.
On the other hand, anybody with some math experience already knows and understands what a function is. At least to these people, Haskell syntax is clearer because it more closely matches something they're already familiar with: defining functions by cases. Sure, if you use some weird operators from odd libraries, people won't be able to follow. But that's true of using odd libraries in any language: people won't inherently understand AbstractBeanFactories or __magic_names__ either!
Now, if you already have some programming experience and little math, it's a completely different story. Once you've seen one imperative language with loops, statements and variables, you've seen them all. But this says more about how similar they are them about how easy they are to understand without background.
The usual experience people have with teaching Haskell and Scheme is that it's actually easier for people without prior programming experience! Colleges starting with either of these languages use them partly to level the playing field, and it seems to have worked reasonably well.
Besides, C and especially C++ are both very difficult to pick up. This hadn't stopped them from being people's first languages and becoming extremely popular. There's definitely much more to the equation, and I think the perceived difficulty of learning is both less important and less pronounced many people believe.
For a few years I got to watch a lot of novices and young programmers come to grips with various topics/programs together while I was helping out with a CS summer camp for prospective students at university. One year I was involved we used Pascal, another year we used JavaScript, but for a number of years, we used... Prolog!
This was done partly because prospective CS students often already knew Pascal, JS, or both -- putting the curriculum in a lesser-known language provided some extra incentive for those looking to stretch themselves.
The other thing, though, is that it seemed to put our smart but novice students on more equal footing with our students who already knew how to program. That is, though Prolog was arguably "harder", our novices seemed to keep up.
I suspect that Prolog isn't really harder, it just requires some thinking on an orthogonal axis to more common languages. Most of us don't get much practice on that axis, so writing programs in it is difficult.
The same thing may well be true of Haskell and Lisp.
"There is no reason why you cannot combine strong types or optional types with LISP, in fact, there are already LISP dialects out there that did this."
Common Lisp already has strong, dynamic, optional types.
"Strong" means: there is no implicit type conversion.
"Dynamic" means: runtime things (objects) have a type, not necessarily the (static) variables that hold them. This is also called "late binding".
"Optional" means: you need not specify a type for everything; types can be inferred from context.
> "There is no reason why you cannot combine strong types or optional types with LISP, in fact, there are already LISP dialects out there that did this."
> Common Lisp already has strong, dynamic, optional types.
Isn't that what he said? Common Lisp is a dialect of Lisp.
we usually record every talk, but there was an equipment malfunction that night so unfortunately there's no video.
videos of other talks are at http://lispnyc.org/meetings. we're pretty awful at getting the videos up in a timely manner, and by "we" i mostly mean "me".
"Haskell and LISP both have minimal syntax compared to C++, C# and Java". I agree that LISP does but I can't really say the same thing for Haskell, especially when you get into the whole monad stuff...
It isn't descended from Prolog either -- I presumed the author was making a point about conceptually similar flavours of type systems, semantics etc. and Haskell's position as a typed Lambda calculus.
I thoroughly recommend "The Art of Prolog" which is an engaging and fun read.