SWI-Prolog extensions in version 7
swi-prolog.org
swi-prolog.org
http://www.swi-prolog.org/pldoc/man?section=maps
That is exciting. I'd want to play with it again. I like Prolog. Or rather, I like idea of Prolog, until I go to solve a problem and it breaks my brain. I love seeing elegant solutions to complicated problems in 10 lines of code, but also realizing there is little chance of me coming up with those solutions.
Other languages, functional, OO, imperative, I can often iteratively improve a solution. It goes from wrong,better, even better, almost works, good enough. With logic languages it goes from wrong, wrong, wrong, x100 ..., aha I got it and it is beautiful and short.
Also speaking of maps, Erlang is probably going to get them too in the next release early next year -- R17, https://github.com/erlang/otp/tree/egil/maps/eep-implementat....
Prolog has always had that. You declare facts like parent(patricia, shelly), and you cant make this at run-time too with assert and retract. Unification & resolution makes this work like a 2-way map. What's the big deal now?
http://www.swi-prolog.org/pldoc/man?section=ext-maps-usage
http://www.swi-prolog.org/pldoc/man?section=ext-maps-motivat...
Sorry, I'll take SWI-Prolog developers' word over yours in this case.
Your argument is a bit like the "Well this old existing language is Turing complete, so why bother with anything".
Except that he is right that Prolog facts (and other clauses) can be used as a mapping. At the very least, modern Prolog implementations index on the first argument (compute the hash code and look that up). So, you get similar properties to a hashmap: you can look up in O(n) time and get an associated atom/term/...
However, multiple clauses can match a query. For instance, given
foo(bar(x),1).
foo(bar(y),2).
the query foo(bar(_),X) creates a backtracking point (both facts unify, so X will be bound to x and y subsequently). SWI-Prolog's new maps behave more like normal maps in that there cannot be duplicate keys. However, you could enforce that with Prolog facts as well: assert_unique(parent(X,Y)) :-
retractall(parent(X,_),
assert(parent(X,Y)).
assert_unique(parent(jack,john)) will ensure that any parent(jack,_) facts are removed before asserting the new fact.>
assert_unique(parent(X,Y)) :-
retractall(parent(X,_),
assert(parent(X,Y)).
Maybe to you that looks like an example why maps are _not_ needed as they just reinvent the wheel or something. To me it looks like an example why maps _are_ needed.That works fine.
How does a 3 level deep map work with clauses
The most straightforward manner is like you would do this in a relational database (if the goal is to keep O(1) times). E.g. two-level:
foo(a,x).
foo(b,y).
bar(x,a-x-one).
bar(x,a-x-two).
bar(y,b-y-one).
Again, you can add predicates to make this less unwieldy.If the JSON conforms to a schema, there is also the possibility of mapping particular keys to arguments. Since you know the set of possible keys in such a case, you could map keys to fixed term arguments. E.g. a structure such as:
{ "foo": "apple", "bar": "pear" }
Could be mapped to: json(apple,pear)
You would have the same You could do this for deeper maps as well. It gives you the same benefits as hash maps, O(1) indexing. In fact, the Hdrug[1] system uses such a representation for partially typed feature structures, which can have an arbitrary depth. It provides a DSL for easily specifying types (the 'schema') and unifying structures and substructures. There is also a short description in the introductory chapters of my thesis, though it is definitely not my work ;).Note: I am not for or against adding maps to the language. There are probably applications where they are very handy in Prolog. For the things I worked on in Prolog I never really needed first-class maps.
[1] http://www.let.rug.nl/~vannoord/Hdrug/
[2] http://danieldk.eu/Research/Publications/phd-thesis.pdf (starting at the end of page 19)
In portable Prolog code, you can only really make the assumption that the first argument is indexed, if it is an atom or a term (in the latter case the functor and arity is used).
In other words, if you have many parent/2 facts
parent(patricia,X).
will be a constant-time lookup, while parent(X,shelly).
will not be. Another thing to keep in mind is that there can be multiple clauses that unify with a goal.Real-world story: in the natural language generator that I co-developed, we rewrote every grammar rule with term expansion, such that the attribute-value structure for the syntactic head was the first argument. In this manner, lookups of grammar rules are much faster, since you only have to try to unify with the rules with the corresponding syntactic category.
tl;dr Prolog facts can be used to create mappings. Don't use them as a two-way map without extra precaution if you have a large number of facts.
In my experience, it only works like that when you are fairly new in the language. Later it works like most other languages: build small and understandable predicates. Compose and refine.
Another reason that it's usually easy to move to a working version in Prolog quickly is that the tracing capabilities in most implementations are excellent. So, it's really simple to see if a predicate works as you expected to, since you can walk through a proof step by step.
What's harder in Prolog is that it is relatively easy to mess up predicates such that they are not 'steadfast'. In the words of the inventor of this term: "Steadfastness basically means that you cannot force a predicate down the wrong path by filling in output arguments wrongly."[1]
[1] http://blog.gmane.org/gmane.comp.ai.prolog.swi/month=2009030...
Interesting. Yeah is how I often mess up. The backtracking just ends up going the wrong way.
Are you familiar with Mercury, what do you think of it. They add besides type, also predicate determinism. Something like (copy paste from its example code):
>
:- mode append(in, in, out) is det.
:- mode append(out, out, in) is multi.
Here they determine various determinism modes of predicate append. Do you see that as a good improvement? Very useful? Or a nice to have option?It's great for those kinds of problems, because backtracking search is built-in to the language. But it's a terrible language for doing anything bigger.
Mercury (http://mercurylang.org) is a very interesting successor language that has lots of modern, Haskell-like features like strong typing and type classes.
Now, I think I may have that project. We're at a point with some of our projects to where we are extracting structured information (as RDF) from unstructured content, and storing that RDF in a triplestore, and allowing SPARQL queries. So you can do things like asking for system for all "entries" (where an "entry" can be a tweet, a blog post, an email message, etc.) where say, "all entries that mention a musician who was born in the UK" or "all entries that mention a college or university in the US, founded after 1800" or whatever. Of course, normals don't write SPARQL queries, which leads us to doing a certain level of natural language understanding, and then automatically generating the corresponding SPARQL.
As it happens, Prolog has long been associated with NLP and there is quite a bit of literate on doing this kind of work with Prolog. So now I'm very excited about a chance to learn Prolog and apply it to a problem that I find very interesting.
Aside: Yes, I am aware of Quepy[1], which does this in Python. But I also want to learn Prolog for other reasons as well, and want to spend at least a little bit of effort exploring doing in Prolog. But if it proves to be too challenging to get something working, we may use Quepy.
It is heartening to see the icon in the task switcher: http://twitpic.com/dmc8pb