[mercury-users] Re: Lisp-like syntax for Mercury (Mercury & macros)

Milan Zamazal pdm at zamazal.org
Fri Jun 7 19:03:02 AEST 2002

>>>>> "RB" == Ralph Becket <rafe at cs.mu.OZ.AU> writes:

    RB> There is a more direct translation:

When I've already accepted the previously mentioned practical troubles
of the translation, it's better to target directly and completely on
Lisp lovers.  So I prefer Lisp look and readability over the direct
translation.  I gave up on straight readability to Mercury programmers
who use the standard Mercury syntax.  I'm sorry, but trying to get
everything often results in nothing :-(.

    RB> The thing is, if you just want term_expansion (= Lisp) style
    RB> macros, you can just use the expand_terms.m approach in the
    RB> samples directory.  Certainly some nicer syntax could be
    RB> provided, but you don't need to shift to S-expressions to
    RB> achieve your goal.

Yes, but I'm getting to like Mercury in s-expressions :-) and the vision
of using Mercury within Lisp.

>>>>> "RAO" == Richard A O'Keefe <ok at cs.otago.ac.nz> writes:

    RAO> Milan Zamazal <pdm at zamazal.org> wrote:
    RAO> - Good editor support
    RAO> (as a former participant of an attempt to create a modern
    RAO> Prolog mode for Emacs, I know how painful Prolog's syntax is
    RAO> from the point of view of editor support).
    RAO> That's odd.  My tiny Emacs-ish editor (thief/top) has what I
    RAO> consider to be good support for Prolog (like it can detect
    RAO> syntax errors and singleton errors, knows the beginning of a
    RAO> predicate when it sees one, and can step over Prolog goals &c)
    RAO> and it was *EASY*.  Mind you, I didn't have to fight Emacs lisp
    RAO> to do it...

How about font-locking with things like heavy overloading of the quote
character (0'a, 'term'(...), 'string')?  How about automatic indentation
(e.g. 3.14 versus `.' as the end of clause)?  What if I better read
terms with the parentheses separated from the functor, e.g. `term (Foo)'
instead of `term(Foo)'?  All that is solvable in Emacs, but no way

    RAO> 	(defmodule sort
    RAO> 	  (:export main))
    RAO> What happened to the arity?

It's intentionally omitted as well as the type specification.  I think
it's not a good idea to export only a certain part of the predicate
definitions put under the same name.  I also don't like defining
predicates with the same name and different arity too much, but that
might be just a complex introduced by my Java programming.

    RAO> 	(define main (* *)
    RAO> 	  (:types (io:state io:state)
    RAO> 	   :modes ((di uo :det)))

    RAO> This strikes me as rather un-lispy.  Why not

    RAO> 	(define (main (W0 io:state) (W io:state))

This is what I tried at the first attempt, but I've found it a bit
unreadable.  The problem is that you must specify types for all the
arguments in Mercury, and there are often many arguments in logic
programming.  This is unlike defmethod, where you usually qualify only
one or two arguments.  Consider additionally the multiple modes and you
can see the most natural way is probably not the best way.

BTW, it's not completely unlispy, see `declare type'.

    RAO> 	  "Some documentation."
    RAO> 	  [io:command-line-arguments Args]

    RAO> Here I part company with you.  The use of square brackets is common
    RAO> in some Scheme dialects, and was known in Interlisp (where brackets
    RAO> were "stronger" than parentheses, so [(((x] was legal).  But it is
    RAO> not part of normal (Common) Lisp practice, nor blessed by any version
    RAO> of the Scheme report.

Prolog and Mercury clearly separate terms and lists and I like it.
Would you like to suggest a better term notation than the square

    RAO> 	  (or [= Args '()]
    RAO> 	      [handle-args [no] [no] * *]
    RAO> 	      [sort * *]
    RAO> 	      /

    RAO> I haven't the faintest idea what / might be.  In Marseilles Prolog
    RAO> it was the cut.  OHHHHH, I see.
    RAO>     (or g11 ... / g21 ... / g31 ...)
    RAO> really means
    RAO>     (or (and g11 ...)
    RAO>         (and g21 ...)
    RAO>         (and g31 ...))
    RAO> I can't help thinking that using 'and' would be lispier than
    RAO> using /.

It would be lispier, but AND is so common in logic programming that
using it explicitly makes the sources unreadable.  I no way insist on
using `/' -- it's just a randomly selected character that can be typed
without pressing Shift, doesn't conflict with common Lisp syntax (which
doesn't apply to `;' unfortunately) and makes a good visual separation.

And I've also thought Ralph Becket would be glad to see a bit of infix
notation in the syntax ;-).

    RAO> 	      [= Args '(Input)]
    RAO> 	      [handle-args [yes Input] [no] * *]
    RAO> 	      [sort * *]
    RAO> 	      /
    RAO> 	      [= Args '(Input Output)]
    RAO> 	      [handle-args [yes Input] [yes Output] * *]
    RAO> 	      [sort * *]
    RAO> 	      /
    RAO> 	      [= Args '(_ _ _ . _)]
    RAO> 	      [io:write-string "Usage: sort [Input [Output]]~%" * *]))
    RAO> I really have trouble understanding what the stars mean.
    RAO> (Some Prolog dialects have used "*" the way Edinburgh Prolog uses "_".
    RAO> That threw me.)  If a quaint abbreviation is to be used, wouldn't
    RAO> ":io" be clearer than "* *"?

There have to be a distinction between DCG "invisible" variables and
anonymous variables.  I like the idea using :io instead of `* *'.  (OTOH
I don't like the idea to expand the DCG variables by hand as shown
below, it's very bothering.)

    RAO> Here it is in a lispier style.

    RAO> 	(define (main (W0 io:state) (W io:state)
    RAO> 	              :modes ((di uo :det)))
    RAO> 	  "Some documentation."
    RAO> 	  (io:command-line-arguments Args)
    RAO> 	  (case Args
    RAO> 	    (()
    RAO> 	      (handle-args (no) (no) W0 W1)
    RAO> 	      (sort W1 W))
    RAO> 	    ((Input)
    RAO> 	      (handle-args (yes Input) (no) W0 W1)
    RAO> 	      (sort W1 W))
    RAO> 	    ((Input Output)
    RAO> 	      (handle-args (yes Input) (yes Output) W0 W1)
    RAO> 	      (sort W1 W))
    RAO>             ((_ _ _ . _)
    RAO> 	      (io:write-string "Usage: sort [Input [Output]]~%" W0 W))))
    RAO> If something is going to use a lispy syntax, then since 'case' is part
    RAO> of Lisp syntax, 'case' might as well be used.

Yes, `case' can be easily defined as a macro expanding to a proper
Mercury syntax.

    RAO> On the other hand, distinguishing between W and w isn't really
    RAO> very lispy.  This isn't going to be pretty, but it's arguably
    RAO> lispier:

    RAO> 	(define (main (,W0 io:state) (,W io:state)
    RAO> 	              :modes ((di uo :det)))
    RAO> 	  "Some documentation."
    RAO> 	  (io:command-line-arguments ,Args)
    RAO> 	  (case ,Args
    RAO> 	    (()
    RAO> 	      (handle-args (no) (no) ,W0 ,W1)
    RAO> 	      (sort ,W1 ,W))
    RAO> 	    ((,Input)
    RAO> 	      (handle-args (yes ,Input) (no) ,W0 ,W1)
    RAO> 	      (sort ,W1 ,W))
    RAO> 	    ((,Input ,Output)
    RAO> 	      (handle-args (yes ,Input) (yes ,Output) ,W0 ,W1)
    RAO> 	      (sort ,W1 ,W))
    RAO>             ((_ _ _ . _)
    RAO> 	      (io:write-string "Usage: sort [Input [Output]]~%" ,W0 ,W))))

I agree, but practical matters play role here.  I don't like the Paul
Graham's notation of Prolog variables (`?var') for two reasons: It
requires pressing Shift and it makes each variable name one character
longer, thus requiring much more line breaks in logic programming.  The
comma syntax fixes only the first problem.

    RAO> Hmm.
    RAO> #main(io:state,io:state)-det(di,uo).
    RAO> +main(W0,W)-io:command_line_arguments(A)-main_body(A,W0,W).

    RAO> #main_body(list(string),io:state,io:state)-det(in,di,uo).
    RAO> +main_body(nil,W0,W)    -handle_args(no,no,W0,W1)        -sort(W1,W).
    RAO> +main_body(I.nil,W0,W)  -handle_args(yes(I),no,W0,W1)    -sort(W1,W).
    RAO> +main_body(I.O.nil,W0,W)-handle_args(yes(I),yes(O),W0,W1)-sort(W1,W).
    RAO> +main_body(_._._._,W0,W)-io:write_string("Usage: sort [In [Out]]\n",W0,W).

    RAO> Maybe we abandoned Marseilles Prolog syntax too soon?  (:-)

No, it would be only a half step :-).

Thank you for your comments.

Milan Zamazal

As is typical in civilized (i.e., non-corporate) email discussions, my
remarks *follow* (not precede) their context.
                                   -- Branden Robinson in debian-legal
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe

More information about the users mailing list