Q: functional/equational language, smells a little of Python

John J. Lee jjl at pobox.com
Sat Jun 4 17:54:01 EDT 2005


Saw this on LWN:

http://q-lang.sourceforge.net/


Looks interesting, and reminiscent of symbolic algebra systems like
Mathematica.  Also, the website mentions dynamic typing and "Batteries
Included", which made me think of Python.  Damned silly name, though
(perhaps pre-Google?).

Anybody here used it?

Snippet from the FAQ:


 2. Yet another "Haskell for the poor"?

Not quite. Even though the syntax and some of the stuff in the
standard library looks superficially similar, Q is different in a
number of ways:

    * First and foremost, Q is an equational rather than just a
      functional language, meaning that it is based on general term
      rewriting instead of the lambda calculus (which is just one, and
      very special, rewriting system). In particular, Q has no a
      priori distinction between "constructors" and "defined" function
      symbols, and argument patterns are not restricted to
      "constructor terms". This allows you to have symbolic evaluation
      rules like the following distributivity rule: X*(Y+Z) =
      X*Y+X*Z. Such rules are not allowed in ML and Haskell because
      they violate the "constructor discipline". Moreover, the Q
      interpreter also happily reduces expressions involving
      variables, so that you can try your definitions with symbolic
      inputs (e.g., map F [X,Y] will evaluate to [F X,F Y]), which is
      quite useful for debugging purposes.

    * While other functional languages are either "eager" or "lazy", Q
      tries to give you the best of both worlds: It uses eager
      (call-by-value) evaluation by default (which lends itself to an
      efficient implementation), but also allows you to define your
      own special forms, which can be used to implement both
      call-by-name functions and lazy data constructors. Using special
      forms you can also define your own "meta functions" which
      manipulate arbitrary (not necessarily irreducible) expressions
      as literal terms. This gives you full control over the reduction
      strategy, where this is desired, as well as a kind of "macros"
      and "self-modifying programs", since constructs like lambda
      abstractions can be analyzed, transformed and constructed in
      many ways before they are actually evaluated.

    * Q uses dynamic typing. This has become a rare feature in
      contemporary functional languages, which usually employ a
      Hindley/Milner type system which offers more safety at the
      expense of restricting polymorphism. Q gives you back the
      flexibility of good old Lisp-style ad-hoc polymorphism and even
      allows you to extend the definition of existing operations
      (including built-in functions and operators) to your own data
      types. Moreover, Q has a Smalltalk-like object-oriented type
      system which supports data encapsulation and (single)
      inheritance. This makes it possible to manage complex,
      polymorphic data with ease.

    * Q takes the pragmatic route in that it provides (monad-free)
      imperative programming features such as imperative I/O and
      mutable data cells, similar to the corresponding facilities in
      ML. While one may argue about these, they certainly make life
      easier when programming complex I/O stuff such as graphical user
      interfaces.

    * Last but not least, the Q programming system comes with
      batteries included. There are quite a few add-on modules
      interfacing to third-party libraries which, while not as
      comprehensive as the facilities provided by traditional
      scripting languages like Perl and Python, allow you to tackle
      most practical programming problems with ease. In particular,
      multimedia and computer music is an area where Q shines,
      providing facilities to handle graphics, digital audio and MIDI
      in a convenient and efficient manner (efficient enough for soft
      realtime applications), which go well beyond what is currently
      being offered for other functional languages.


Some of Q's flexibility comes at a price. In particular, Q's symbolic
evaluation capabilities as a term rewriting language dictate that the
language is essentially exception-free. This means that an
"ill-formed" expression (such as "division by zero" or, more
generally, the application of a function to data for which there is no
corresponding definition) does not, by default, raise an exception,
but instead the expression is already in "normal form", i.e., it
evaluates to itself. As a remedy, Q provides facilities to add
explicit error rules which raise exceptions, and to handle exceptions
in a suitable manner. Another limitation is that Q does not allow you
to have arbitrary local definitions in the style of Haskell and ML's
"let" and "where" clauses. In Q, "where" clauses are limited to
variable definitions (similar to Haskell's pattern bindings), but
local rewriting rules are not supported as they would wreak havoc on
the term rewriting semantics.

You will also notice that Q lacks most of the syntactic sugar found in
Haskell. This is partly due to my laziness, but it also keeps the
language and the core system simple. Using Q's symbolic processing
capabilities, the usual bits like lambda abstractions, pattern
matching conditionals and list comprehensions can easily be written in
Q itself (although this does not offer quite the same performance as
when they are provided as builtins, of course).


John



More information about the Python-list mailing list