So, I've been using the Mercury programming language for a little while now. I've kind of wanted to learn it for many years, but it's extremely different from any other language that I properly know, so until now I haven't really been able to even begin learning it.
I thought I would share what I've learned about it, because I am really happy that I am finally making progress learning it, and because I think it is a really nice language.
Mercury is a functional language, influenced by Haskell, but it's also heavily influenced by the logic language Prolog. All I really know about Haskell is that it is purely functional, declarative, and has a powerful type system. I don't really know much of anything about Prolog. That, and people say "Haskell is unrealistic about some things because it's a research language", and "Prolog is slow". I do know that Mercury has a very similar syntax to Prolog and a very similar type system to Haskell.
What you know about Prolog and Haskell is kind of important when learning Mercury. I found out very recently that almost everyone using it came over from Haskell or Prolog. Which explains why I had such a hard time even beginning to understand it--all the documentation assumes you know either Prolog or Haskell.
So, without knowing much about its roots, what do I find interesting about Mercury?
Mainly, how it allows you to express the state of a program. I
think this is a good example of the interplay of logic and functional programming:
% from a small directory searching routine
% This is a disjunction. The closest thing you could relate it to in imperative programming is a set of logical-or statements, or kind of a switch statement.
% PathType has been assigned, OutPath has not been assigned yet. Both are a 'maybe' type.
(
PathType = yes(directory),
OutPath = yes(InPath)
;
% After each semicolon is another possible state.
PathType = yes(file),
OutPath = yes(InPath)
;
PathType = no,
OutPath = no
)
In that case, PathType is a variable that has a state already. If it is equal to `yes(directory)' or `yes(path)', then the OutPath variable (which had not been assigned a value yet) is now set. Otherwise, this predicate (kind of the same thing as a function) fails.
With SLD resolution (which I'm told is inherited from Prolog), the idea of left-hand and right-hand expressions doesn't exist. Either a state is possible or its not. So what stops PathType from being reassigned? In Functional languages, a variable can only be assigned once. That's the combination of logical and functional programming: You describe the state, and if the state is possible based what values have been assigned, it becomes so. If two states are possible, but mutually exclusive, the compiler will know and your program won't compile.
To this end, there are many nice ways of expressing logical relations, such as the disjunction. While in that example it assigns to OutPath, the entire disjunction (everything in the parentheses) is itself a boolean expression. If any of the states it lists are possible, it is true. It's an expressive logical-or statement! There is a similar expression, a conjunction, which is the same as a logical-and statement. In fact, it's written using commas instead of semicolons. Which means that everything is either a huge logical-and statement, logical-or statement, or combination of the two. Your entire program can be said to be true or false, deterministic or non-deterministic. This means that it's simple to statically analyze the program and determine if a predicate has one solution, many solutions, or no solutions. Similarly, it's simple to see what predicates may fail.
Of course, there are a LOT of things I still need to learn. The determinism system in Mercury is much deeper than I understand right now, and I don't fully understand functional purity. But now that I'm actually making progress, and I understand some of the foundations of logic and functional programming, I'm rather enjoying learning Mercury.