
The Mercury logic programming system - pplonski86
https://github.com/Mercury-Language/mercury
======
vore
No mention of Mercury is complete without mentioning PrinceXML, the only
software I have ever seen using Mercury in production:
[https://www.princexml.com/doc-
refs/#acknowledgments](https://www.princexml.com/doc-refs/#acknowledgments)

~~~
alhimik45
Hmm, converting HTML to Pdf doesn't look like a task for logic programming
language. Why did they choose Mercury?

~~~
ainar-g
That's a peculiar opinion. Usually, whenever discussion comes to parsing and
codecs, people like to mention how the problem P could be solved with a purely
functional language L so much more elegantly. And yes, logic and purely
functional languages are not the same, but they seem to be very close
relatives.

~~~
tluyben2
I mentioned to my Haskell teacher in uni that I did 2 years of intensive
Prolog for an AI course at another uni and so that I grasp the basics or
‘everything recursion’ (mind you, this is 25 years or so ago). He got angry
and said the two have nothing in common and if I believe that I definitely
should pay more attention. It was weird as I did not say they are alike; just
that they share some concepts which are usually hard to understand for
imperative programmers, but, after 2 years of breathing Prolog really are
second nature.

~~~
ainar-g
Honestly, that speaks more about the teacher's personal issues than it does
about the similarities between logic and purely functional programming. I'm
sorry that you had to experience that.

------
pmontra
The are examples in the wiki, but there are no references to that in the repo
README. The authors should fix that.

This is the hello world

    
    
        :- module hello.
        :- interface.
    
        :- import_module io.
    
        :- pred main(io::di, io::uo) is det.
    
        :- implementation.
    
        main(!IO) :-
            write_string("Hello, world!\n", !IO).
    

My first reaction is why that :- at the beginning of the first lines? I'm sure
there are pretty good reasons for it, probably because of the history of this
lineage of programming languages.

That's fine if the authors are interested only in developers from that
background. If they want to expand to the general developers community they
should adopt a more mainstream syntax which will ease onboarding. Elixir gave
a nice lesson about that, by giving Erlang a Ruby like syntax and onboarding
many developers from non functional languages. Then Elixir is still Erlang and
functional.

Probably the interpreter/compiler can do some more work and be able to
understand what module, interface, import_module, pred and implementation are
without the :- prefix. To my eyes that :- is only noise, I don't need it to
read and understand the program. The language should help me, not the other
way around.

Other points along the same line:

* The ! before IO reminds of the not operator in other languages and I wonder what it means. I should read the documentation but it feels strange.

* The :- again after the function definition. Other languages have either simpler characters to type (Ruby and Elixir have do, Python has :, C and Java have { ).

* The . at the end of statements. From other examples it seems that Mercury uses it exactly as Erlang does (one(), two(), three().) Elixir managed not to use neither commas nor the full stop. It uses do end instead ({} is more popular). Python use a different approach which I don't like but it's popular too.

~~~
triska
Mercury's roots are indeed the explanation and justification for many of these
points: Mercury syntax is deliberately designed to be very close to Prolog
syntax. In fact, it is so close to Prolog that if you remove the declarations,
then many Mercury programs are also valid Prolog code.

Regarding ":-", there is a difference between writing:

    
    
        :- implementation.
    

and

    
    
        implementation.
    

The latter is a _fact_ and can be read as "implementation holds". The former
is a _directive_ that tells the compiler something.

As in Prolog, :- is an ASCII transliteration of ←, i.e., an arrow from right
to left. A clause of the form:

    
    
        Head :- Body.
    

is read as: " _If_ Body is true, _then_ Head is true.". Such clauses are
sufficient to describe every known computation.

In Mercury, !Var is a _state variable_. It is a shorthand for naming
intermediate values in a sequence. Without using state variables, you can
write the code equivalently as:

    
    
        main(IO0, IO) :-
            write_string("Hello, world!\n", IO0, IO).
    

State variables are more explicit than using DCG notation, and at the same
time still easier to write than pairs of variables that are threaded through.

The "." at the end of clauses is likewise inspired by Prolog syntax.

Please note that Prolog programs are, syntactically, also Prolog _terms_ , and
"." is used at the end of each clause.

~~~
YeGoblynQueenne
>> Please note that Prolog programs are, syntactically, also Prolog terms, and
"." is used at the end of each clause.

Heh. You won't believe how much trouble I got into for using Prolog
terminology like "term" and "predicate" when speaking to logic programming
people, even though they all know Prolog perfectly well.

You can probably imagine why- in FOL, and so in logic programming, a "term" is
a variable, a constant or a function, and a "predicate" is a concept. In
Prolog, a "term" is - well, everything! And "predicate" is either a clause or
what LP people call an atom. Oh, and, btw, an "atom" in Prolog is either a
predicate symbol, a non-ary function, or a constant, whereas in LP it's a
predicate symbol followed by a vector of terms in parentheses.

How all this terminological confusion came about, I don't know, but I'm sure
suffering because of it, and because I first learned Prolog, before really
studying logic programming, as such.

~~~
triska
The terminology of first-order logic is indeed quite different from that of
Prolog. A key reason for this is that in FOL, we have to distinguish between
the syntactic entities and their interpretations. So, in FOL, we have
predicate _symbols_ that are assigned to _relations_ by an interpretation, we
have constant _symbols_ that are assigned to domain _elements_ by an
interpretation, we have function _symbols_ that are assigned _functions_ by an
interpretation. In addition, many theorems also require that we distinguish
between countable and uncountable signatures.

In contrast, Prolog is confined to a single _kind_ of interpretations, namely
to _Herbrand structures_ , where each term "stands for itself", and where we
only need symbols that _already occur_ in the clauses we are considering:

[https://en.wikipedia.org/wiki/Herbrand_structure](https://en.wikipedia.org/wiki/Herbrand_structure)

So, in Herbrand structures, the interpretation of a term T is simply the
symbolic representation of T, i.e., "T". Importantly, one can show that a set
of clauses has a model if _and only if_ it has a Herbrand model.

This also has important semantic consequences: For example, due to the
compactness theorem (and its consequence, the upward Löwenheim–Skolem
theorem), one can show that important concepts such as the _transitive
closure_ of a relation, the class of _connected graphs_ , and the _natural
numbers_ with only the intended model (up to isomorphism) _cannot be expressed
in first-order logic_!

[https://en.wikipedia.org/wiki/Compactness_theorem](https://en.wikipedia.org/wiki/Compactness_theorem)

Yet, we can readily express these things in Prolog, and in fact almost every
Prolog program also does that or needs them!

Why? Because Prolog (implicitly) only considers _least Herbrand models_ , so
we do not need this layered syntactic view, and also do not run into these
semantic issues when programming in Prolog.

An argument can be made that in this case, what at first seems like a
restriction in fact extends the usefulness of the language. A similar argument
can be made also for several constructs _within_ the language.

~~~
nmadden
While Prolog’s operational semantics are given in terms of least Herband
models (at least, before you consider negation), you can also view a Prolog
program as a subset of FOL and give a traditional model-theoretic account of
the semantics. This may be less useful practically, for the reasons you give,
but sometimes it’s nice to consider that a symbol “fred” might actually refer
to a person called Fred rather than just be symbols all the way down...

(It always surprises me when Prolog texts refer to the least Herband model as
the “intended model” - it’s definitely not what I intend when I write Prolog!)

So while we can say that an “ancestor” relation in Prolog correctly defines
transitive closure within the least Herbrand semantics, at some point we
actually have to relate that “semantics” to the real world if we want to know
what our programs mean.

Edit: putting this all another way, my understanding of (pure, positive)
Prolog’s operational semantics is that the least Herbrand model contains
exactly those sentences that are true in all models of the program, whether
those models are Herbrand or otherwise. So it’s not quite true to say that
Prolog only considers the least Herbrand model, but that it may as well only
do so because the (operational) result will be the same. It’s been a while
since I’ve looked at this any great depth though.

~~~
YeGoblynQueenne
>> (It always surprises me when Prolog texts refer to the least Herband model
as the “intended model” - it’s definitely not what I intend when I write
Prolog!)

Good point.

------
garyclarke27
Anyone know how this compares to Picat? I spent some time looking at Picat and
plan to use it in the future in an (mainly SQL) ERP system for solving
constraint decision problems. Picat is v nice, I could never get my head
around Prolog, Picat is much easier for me to grok and appears to be a lot
more powerful.

------
tluyben2
This language has been around for ages and does not get enough attention imho;
it is a very fast Prolog like and it has been robust for a while now. But
almost no one uses it unfortunately...

~~~
colanderman
I used Mercury intensively for about a year a while ago. I think what
ultimately turned me off was the incompleteness of the implementation (several
of the most interesting features were only 80% implemented, and the
unimplemented corner cases were undocumented and caused the compiler to crash,
so you just had to guess what it was you were doing that was too advanced),
and the incomprehensibility of the error messages (an order of magnitude even
more incomprehensible than C++ template errors).

Notably, the lack of support from the instantiatedness system for partially
instantiated structures put Mercury at a big disadvantage to Prolog's
expressiveness in my opinion.

So now, instead of using Mercury and wishing it better supported partial
instantiation and had comprehensible error messages, I use Prolog and wish it
had even a basic static analyzer and support for the !Var and @Var syntaxes.

------
alexchamberlain
I'm sure this is awesome, but there's no code examples until I download a read
a PDF tutorial. I think a couple of examples in the README or on the homepage
could go a long way. What differiates this from Prolog or Datalog?

~~~
kiriakasis
More expressive than datalog, faster than Prolog.

~~~
lpu4o74p
However, less expressive than Prolog

~~~
srean
Could you explain or point to any discussion on why would that be.

~~~
bjz_
Mercury brings a bit more sanity to Prolog with its mode system. This is one
of the key reasons why it runs fast and can be used to build big systems like
Prince. That said, it _is_ a restriction on expressiveness of programs, and
sometimes that makes it hard to do certain things. That's true of any type
system.

There's still an interesting question about whether a different iteration on
the mode system could capture more of the semantics of Prolog while still
being useful, but so far nobody has done that research yet. It's more trendy
to do FP research these days, so I'm expecting it could be a _long_ time
before we get an answer, sadly.

