Impressions of Mercury

I’ve been using Mercury for a while and I think I’ve gotten enough experience to talk a bit about my first impressions.

  • state variables — useful but hacky. Basically, Mercury’s version of haskell’s side effect sequestering involves threading a useless unique variable through all IO predicates (much like GHC’s implementation of Haskell’s IO monad, actually). So !IO (the name can be anything, not just IO) is preprocessed into something like IO1, IO2, except that the next time you write it it becomes IO2, IO3 and so on. The entire exercise seems a bit pointless to me since it’s all a hack to get things to occur in the order you wrote them. It’s no worse than any other language, though — it just doesn’t tickle my aesthetic sense of “a principled way to handle side effects”.
  • DCG — a bit like state variables. Instead of writing foo(A, B, !Var) :- do1(!Var), do2(B, BOut), do3(BOut, A, !Var)., you write foo(A, B) --> do1, { do2(B, BOut) }, do3(BOut). It’s not clear why you need to have both of these, or why it’s preferred to use state variables instead of DCG for writing IO predicates. DCG is kind of fun to write though.
  • I wish there was a way to get multiple clauses to desugar to nested if statements instead of plain disjunctions. The haskell style where you write f ConstructorOne = ...; f (ConstructorTwo bleh) = ...; f _ = ... produces nondeterministic or multi-solution predicates, when you usually want either deterministic or semideterministic (at most one solution).
  • Thinking about determinism is fun, though. See Typechecker-directed Epiphanies — I’m getting to the point where I understand how the determinism checker works.
  • Modes are interesting. Essentially, any given predicate might have several different arguments that make sense as “outputs”. In prolog, if I remember correctly, you could just use any argument as an output, even if the code you wrote to define the predicate causes an infinite loop when you try to solve for that particular variable. In Mercury, you have to declare some set of modes for each predicate — a mode is basically “If you want to solve for this set of variables, you need this other set of variables to have a known form, and this mode of the predicate has at least (zero|one) solution and (can|can’t) have multiple solutions.” And then, this is the cool part: Mercury checks to see that each mode you declare is valid. So if you say :- mode Foo(in, out, out) is nondet. :- mode Foo(in, out, in) is semidet., Mercury will actually check that Foo can provide zero or more values for the second and third arguments if the first argument is known, and that it can provide zero or one value for the second argument if the first and third are known. And this is just scratching the surface; there’s even cooler things you can do by defining custom “insts” (instantiation states). I could probably write a whole blog post about how amazing modes are.
  • I’m not actually making very good use of the logic programming style — almost all of my predicates are deterministic or semideterministic and could easily be rewritten as functions. It’s kind of fun to say eval(Arg, Env, ArgOut), eval(Body, [Arg | Env], AppOut) instead of AppOut = eval(Body, [eval(Arg, Env) | Env]), but it’s a superficial kind of fun, like wearing a halloween costume instead of normal street clothes. I wonder if this is because I’m just not good at taking advantage of logic programming or because logic programming isn’t very good for this kind of problem?
  • Unfortunately, a lot of the cooler prospects of the languages are still unimplemented. Things like unique modes on data type fields and partial instantiation states are just not supported yet — as I understand it, if you try to write code that uses these features, you’ll get a compile-time or runtime error. This is really disappointing, but luckily the language as it exists now is already pretty nice to program in.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s