3 ms·
I've been actively trying to learn Prolog for the past few months. It's definitely very different from other languages I've used, and it's changed the way I thi
by lucaswiman 12y ago
I've been actively trying to learn Prolog for the past few months. It's definitely very different from other languages I've used, and it's changed the way I think about programming. Prolog seems to be a really brilliant set of ideas embedded inside a mediocre syntax with poor library support for things that are trivially easy in other languages.
I think Prolog rules can replace a lot of spaghetti code: stuff like "Usually do this, but then other times do this, unless this other thing is true. If there's a parse error, then do xyz and keep going." In ordinary procedural code, the exception cases can dominate the body of a function and may need to be deeply nested, but in Prolog, it's possible to cordon them off or express them at the top level.
I suspect it might be most useful as a DSL you can embed inside of other languages, though I haven't seen a good implementation of that. (The clojure core.logic library mentioned elsewhere looks really promising.)
I think it may also be useful for domain experts to specify simple rules that capture an aspect of their expertise. If you restrict the domain down enough, and work to figure out what predicates are needed, prolog rules can become easy enough to read that you don't need to know much programming to use them. But the devil seems to be in the details of connecting the core logic into a bigger system that actually does something.
For example, the answer for hooking prolog up to a SQL database is "Look at the ODBC library!", which is not a very satisfactory answer. I think you could build a really beautiful ORM system in Prolog, but nobody's done it yet. (Maybe ORM isn't the right phrase, but a clean way of relating prolog queries to database queries and vice versa.)
The syntax is wonderfully simple, but also has almost no sugar for common idioms. The predicate notation makes it somewhat harder to batch up a bunch of attributes into one conceptual "thing" than in other languages. That means you need to keep positional arguments in your head a lot more. I think aping the class constructor and attribute notation of other languages would be helpful like `my_foo(foo, bar:attr, baz:attr) :- [...].` Then you could reference that either as a constructor (`my_foo(a,b,c)` would state that `a.bar=b` and `a.baz=c`) or to generate goals, like `my_foo(foo), other_predicate(foo.bar)`. Prolog is so old that choices like "make '.' the end of a statement" made sense at the time, but haven't stood the test of history.
(Disclaimer: Many of my criticisms may have perfectly valid solutions in prolog. I'm still learning it.)
- PhineasRex 12y agoThis exists. It is called Datalog.
- lucaswiman 12y agoDatalog is a query language, but I haven't found good libraries for the "connector" pieces of translating prolog/datalog predicates to SQL, constructing or syncing schema definitions, and database migrations. It seems like if you want to use Datalog, Datomic is the best option. (But datomic is sort of pricey for commercial use relative to SQL databases like Postgresql.)
- collyw 12y ago"Usually do this, but then other times do this, unless this other thing is true. If there's a parse error, then do xyz and keep going." This is almost exactly like the descriptions I get from my team leader for getting results out of a database. He doesn't think in sets for SQL.
- lucaswiman 12y agoRight. I think this is how a lot of business requirements are specified, since they are frequently constructed by non-programmers. Taking a bunch of cases from a spec document generated by a domain expert and turning them into maintainable/readable procedural code takes a lot of creativity. I think it's easier to express case analysis like this in Prolog.
- abathologist 12y agoWhat sort of library support have you found wanting? While the Prolog ecosystem is admittedly tiny compared to mainstream languages, I have often been surprised by the amount of useful libraries available. I love Prolog syntax. I do think there is room for improvement, but the language is also extremely flexible, and it is very easy to roll your own syntax. Funny enough, so far my many experiments with alternative syntax have mainly had the effect of convincing me of the elegance and power of standard Prolog syntax. While there is no particular reason the '.' should be used to terminate statements (except the resonance with many natural languages in this regard), I think some sort of terminator is necessary to keep the syntax as flexible as possible. Like Lisp, Prolog syntax is isomorphic to its AST. Currently my main gripe with Prolog syntax is that it represents conjunction and delimitation of predicate arguments and list items with the same operator, `(,)/2`. However, that can be fixed in two lines: :- op(1000, xfy, user:(&)). A & B :- A, B. But I'm not sure it really needs "fixing"... Regarding, "batching up a bunch of attributes into one conceptual 'thing'": SWI-Prolog has implemented a special data structure it calls "dicts"[dicts] for this purpose, but I am not very fond of it (and there's a fair amount of concern over the way this implementation breaks compatibility with ISO standards). More traditional solutions are to use lists of "pairs"[pairs], option lists[option], or, for larger data structures and when performance and lookup time is an issue, association lists[assoc] or records[records]. Using the first of these techniques looks like this: my_foo(a, [bar-Bar, baz-Baz]) :- Bar = something, Baz = something_else. get_attr(Pairs, Key-Value) :- member(Key-Value, Pairs). set_attr(Pairs, Key-Value, NewPairs) :- ( select(Key-_, Pairs, Key-Value, NewPairs), ! ; NewPairs = [Key-Value|Pairs] ). ?- my_foo(a, As), get_attr(As, baz-X), writeln(X), set_attr(As, boz-another_thing, Bs), writeln(Bs). something_else [boz-another_thing,bar-something,baz-something_else] As = [bar-something, baz-something_else], X = something_else, Bs = [boz-another_thing, bar-something, baz-something_else]. It might be the case that Prolog's flexible syntax leaves it spoiled for choices here... That being said, it would be straightforward to implement syntax similar to your description, which evaluates and replace attribute accessors in place, using `term_expansion/2` and `goal_expansion/2`. Then you could use `As.baz` in place of the value itself (I've done so before, and this is what the SWI-Prolog's dict expansion does). Even easier, you could use Michael Hendricks' func package[func] to make a function for this purpose. But I've increasingly come to think of Prolog's explicit evaluation as a unique strength rather than a problem to be solved. [dicts]: http://www.swi-prolog.org/pldoc/man?section=dicts http://www.swi-prolog.org/pldoc/man?section=dicts [pairs]: http://www.swi-prolog.org/pldoc/man?section=pairs http://www.swi-prolog.org/pldoc/man?section=pairs [option]: http://www.swi-prolog.org/pldoc/man?section=option http://www.swi-prolog.org/pldoc/man?section=option [records]: http://www.swi-prolog.org/pldoc/man?section=record http://www.swi-prolog.org/pldoc/man?section=record [func]: http://www.swi-prolog.org/pack/list?p=func http://www.swi-prolog.org/pack/list?p=func