4 Introduction For Lisp Folks

First off, Lispers will be happy to learn that Logix has both code quoting and a procedural macro system. Logix programs are not made from lists, they are made from user-defined object types. More on this in 7 - Languages: Extending and Creating.

4.1 Function Calls

The Logix prompt can recognize multiple languages. It initially expects Standard Logix (std). Simple function calls in Standard Logix look a lot like Lisp.

[std]: max 4 (min 5 6)
5

Note parentheses are not required on the outer function. In fact, parentheses do not have the special status they do in Lisp – they are just a scoping operator as in most programming languages. A function-call expression is simply a sequence of expressions:

func arg1 arg2 ... argn

Logix handles first-class functions as does Python – i.e. it is Scheme-like not Lisp-like. The astute reader may be wondering how to call a zero argument function. E.g.

[std]: from random import random
[std]: print random
<built-in method random of Random object at 0x009B0368>

The function was not called. To call it, use a special postfix operator ().

[std]: print random()
0.746969538583

Note that () is a special operator. It is not empty parentheses. (in case you’re wondering, the empty list in Standard Logix is [])

4.2 Other Operators

As well as the function call syntax, Standard Logix has many operators with a rich syntax.

[std]: x = 1 + 2
[std]: print if x == 3: 'good' else: 'oh dear'
'good'
[std]: aTuple = 1, 2, 3, 4
[std]: [x * 2 for x in aTuple]
[2, 4, 6, 8]

4.3 White-space Sensitive Syntax

Blocks are delimited by indentation:

[std]: for x in range 10:
     :    stars = "*" * x
     :    print stars

There are a couple of other tricks done with white-space. More later.

4.4 Lexical Rules

Identifiers in Logix follow C like lexical rules. However, any character can be used when extending the syntax, i.e. when defining new operators (see 7 - Languages: Extending and Creating).

4.5 Python Semantics

Logix is implemented as a font-end to Python, so a good deal of Python semantics are exposed. Lisp folks need to watch out for a few things. One way to go would be to read up on Python (docs.python.org), but for the impatient, here’s a few highlights:

def f(x):
    global g
    g = x

4.6 Symbol Operator

In Logix, # is the comment character. To write a literal symbol in Standard Logix, use ~

[std]: ~foo
~foo

Note this operator has another trick up its sleeve:

[std]: ~("foo".upper() + "!")
~FOO!

4.7 Quasiquoting

Logix supports the back-quote operator just like Lisp:

[std]: `max 4 5
<std: max 4 5>

Unlike Lisp, the result is not a list, but an operator object. In this example, the operator represents a function call.

We can also quote operators:

[std]: `1 + 2
<std:+ 1 2>

The returned value is an instance of the + operator from the language std, with operands 1 2, it reads as a prefix notation of the expression.

Inside the quote, the backslash can be used like the comma in Lisp:

[std]: var = ~x
[std]: ` \var += 1
<base:+= x 1>

(note that the += operator is inherited from another language: Base Logix)

Multiple backslashes can be used to escape nested quotes just as with multiple commas in Lisp.

The \* operator is the equivalent of Lisp’s ,@ i.e. it splices a list into the quoted value.

[std]: l = [3, 45, 21]
[std]: `max \*l
<std: max 3 45 21>

You can evaluate these quoted expressions using logix.eval

[std]: logix.eval `max \*l
45

4.8 Macros

Defining macros is performed hand-in-hand with defining new operators with custom syntax. This is covered in more depth in 7 - Languages: Extending and Creating. By way of a quick example:

[std]: defop 50 expr "++" macro ex: `\ex += 1

Here we have defined a new postfix operator with a binding value of 50, implemented as a macro. The macro function takes a single argument (ex) and returns the expanded code template.

[std]: x = 1
[std]: x++
[std]: x
2

You can experiment and debug using logix.macroexpand and logix.macroexpand1.

[std]: logix.macroexpand `a++
<base:+= a 1>
[std]: logix.macroexpand `player.score++
<base:+= (base:. player score) 1>