Welcome to the Lambda Notebook! This is a tool building on Jupyter that aims to computationally implement the core tools involved in linguistic semantics and pragmatics. The focus is on discrete tools involving logic and the lambda calculus that are the building blocks of theories of compositional semantics in linguistics. Because the project builds on and is well-integrated with Jupyter, it inherits many extremely powerful tools aimed at scientific and interactive computing. Some use cases for the lambda notebook include:
The rest of this document introduces some key concepts about using the lambda notebook targeting linguists who have basic knowledge of semantics, logic, and compositionality (but not necessarily python/Jupyter)
Quick links: [Quick reference.ipynb](/notebooks/documentation/Quick reference.ipynb) | [Metalanguage documentation.ipynb](/notebooks/documentation/Metalanguage documentation.ipynb)
Notebooks: Jupyter Notebook is a particular interface to IPython (and other languages) inspired originally by mathematica notebooks, and is centered around interleaving code with documentation. The lambda notebook is primarily intended to be used in the context of a Jupyter notebook (though it does not need to be).
Cells and running code: Jupyter Notebooks are structured into cells. Each cell contains code or text (typically markdown formatted text). Ordinary code cells contain python code that (in an interactive notebook setting) can be run: To (re-)run a cell you can hit the run button in the toolbar with the cell selected, or hit shift+enter while the cell is selected. A code cell by default has an "output" determined by the last executable line of the cell: as long as the value of this line is not None
, is displayed when the cell is executed. Other code can explicitly display output, e.g. via print
.
If you are viewing this as an interactive notebook, you can hit shift+enter or use the run button on the following cell to see a basic example of a regular python cell:
print("This is the output of a python print command (but not the output of the cell).")
20 + 22
Magics: The lambda notebook relies on a specific kind of cell involving IPython "magics" to do things like interpret lambda calculus expressions. These magics change the mode of the cell or line into one that parse lambda notebook-specific code. Magics that transform an entire cell are indicated by a %%
on the first line, and that transform a line are indicated by a %
. (Advanced note: line magics can involve part of a line of python code.)
One main lambda notebook cell magic is the %%lamb
magic. If a cell starts with %%lamb
, then the rest of the cell will be interpreted as a series of definitions in the Lambda Notebook Metalanguage (LNM). Magic cells can also have a return value, and in the lambda notebook this is typically used to display a formatted version of lambda notebook objects in a way that will be familiar to linguists; the %%lamb
cell magic causes the cell to display any lexical items defined in the cell. The metalanguage is documented in [Metalanguage documentation.ipynb](/notebooks/documentation/Metalanguage documentation.ipynb), and the quick-reference at [Quick reference.ipynb](/notebooks/documentation/Quick reference.ipynb) may also be quite useful.
For example, the following cell illustrates how you can define some basic lexical entries in the metalanguage:
%%lamb
||every|| = lambda f_<e,t> : lambda g_<e,t> : Forall x_e : f(x) >> g(x)
||cat|| = lambda x_e : Cat_<e,t>(x)
||dance|| = lambda x_e : Dance_<e,t>(x)
Each of these lexical entries provides a name for the entry and a metalanguage expression (in particular, a lambda expression) characterizing the value of the entry. These expressions are parsed and converted to structured metalanguage objects that are stored in the lexicon for future use. Lexical entries defined this way are available by name in following python code cells, e.g. every
will now access the lambda function defined above. The python *
operator when used on metalanguage objects performs semantic composition in the sense you may know from linguistic semantics, and the three above lexical entries can be composed as follows in a regular python code cell:
(every * cat) * dance
The *
operator here, which is normally the python operator for multiplication, is "overloaded" to do composition on lexical items (and their results), returning an object that stores composition results. The following cell illustrates one way you can probe further into a composition result, showing all composition steps that led to the result(s).
result = (every * cat) * dance
result.tree()
In this case, there is one fairly straightforward composition path. A CompositionResult
object can be manipulated in various ways; for example, the next cell exemplifies how to access the metalanguage object itself that results from composing these items.
Important catch in understanding how Jupyter runs code: the output of a computation can be saved independently of the code generating the actual computation. Running the above %%lamb
cell defines some lexical items, and as a result renders and displays a piece of the lexicon -- but if you save the notebook and reload, the output will remain without the underlying lexical items being defined. The following cell relies on the result
variable defined in the previous cell. When you reload a notebook, be sure to run all necessary cells. Keep this principle in mind also when running cells out of order.
result[0].content
Unsuccessful composition can also be examined; for example, here is the result of trying to further compose with a property, which leads to no succesful composition paths. The result of every failed composition attempt is shown, including operations that are not FA.
((every * cat) * dance) * dance
Line magics: The lambda notebook also supports several "line magics", which can be mixed in with python code inside a cell. This is indicated by a single %
command at the beginning of a line. The %lamb
magic can be used as a line magic. In addition, a single expression can be displayed using the %te
line magic (standing for typed expression). Note that %te
magics will only display output if they are the last thing in a cell.
%lamb ||dog|| = L x_e : Dog_<e,t>(x)
%te (L f_<e,t> : L x_e : f(x))(L y_e : Dog_<e,t>(y))
A %te
object is not simplified by default, but this can be triggered explicitly; in this case it results in beta reduction as much as possible:
%te simplify (L f_<e,t> : L x_e : f(x))(L y_e : Dog_<e,t>(y))
The result of %te
is a metalanguage object that can be assigned to a python variable and manipulated in many interesting ways:
x = %te simplify (L f_<e,t> : L x_e : f(x))(L y_e : Dog_<e,t>(y))
# show x itself, x's type, the righthand part of x, and the simplification steps that resulted in x
display(x, x.type, x[1], x.derivation.trace())
The metalanguage parser can also be accessed in python mode via the function te
by providing a string argument.
te("(L f_<e,t> : L x_e : f(x))(L y_e : Dog_<e,t>(y))")
Please see the notebook Lambda Notebook Demo.ipynb for many more examples of how to use these two modes. Two reasonably detailed examples of full, research-oriented fragments can be found in fragments/Continuations and quantifier scope.ipynb and in fragments/Variable free binding.ipynb. A good starting point for understanding and extending the lambda notebook is tutorials/Type shifting.ipynb, which goes through the process of adding a variety of type-shifting operations to a compositional system. Many further examples of various things you might want to do are provided as well, and we welcome contributions.
These documentation cells are in another mode where you can write 'markdown'-formatted text; this mode can be chosen from the dropdown box in the toolbar. Also, Jupyter uses the MathJax library to support latex math mode; most equations can be written simply be wrapping them in dollar signs. For example: 'λx:x∈De.x is a cat'. To see what the markdown looks like in this notebook, just double-click on any of the text cells (or hit enter with the cell selected). To re-render it, hit shift-enter.
This is a non-exhaustive list of features that are available in the lambda notebook.
Metalanguage and types:
Object language interpretation:
Some things that are prominently missing:
Contributions are welcome!
The Lambda Notebook is based heavily on the Jupyter Notebook and most of the interface you are seeing is Jupyter. While it may be possible to load some lambda notebook documents in a third-party editor like VSCode, not all features are supported, and so it is highly recommended to use Jupyter itself (e.g., jupyter lab). Here are a few more notes on what exactly Jupyter is that may be helpful if you are new to it.
jupyter lab
, and can stop it by hitting ctrl-c twice.import lamb.auto
to the beginning of the notebook. This is fully equivalent to loading the lambda notebook kernel.