#+Title: Oz demo #+Subtitle: September 9th #+Author: Mark Armstrong, PhD Candidate, McMaster University #+Date: Fall, 2019 #+Description: A quick demonstration of the Oz language #+Description: (and the Mozart2 programming system) for CS-3MI3. * Getting started :PROPERTIES: :CUSTOM_ID: Getting-started :END: The Mozart programming system uses Emacs as an editor, with dedicated keybindings for interacting with the Oz virtual machine. In an Oz buffer (window), use the key sequence ~C-. C-b~ (that is, ~Ctrl-.~ followed by ~Ctrl-b~) to “feed” the buffer to the virtual machine. Another useful command is ~C-. h~, to /halt/ the virtual machine in case of any issue. Note this will lock Emacs up for 30 seconds! The “[[https://mozart.github.io/mozart-v1/doc-1.4.0/tutorial/index.html][Tutorial of Oz]]”, even though it is for the older Mozart v1, is of great use when learning Oz. It was my primary resource when writing these notes. ** Using Emacs help: most things are documented! :PROPERTIES: :CUSTOM_ID: Using-Emacs-help:-most-things-are-documented! :END: For more details on using Oz in Emacs, type ~C-h o~ and then ~oz-mode~ followed by ~enter~. Alternatively, type ~M-x describe-mode~ (where ~M-x~ is “Meta-X”; usually Meta is ~Alt~, so ~M-x~ is ~Alt-x~) followed by ~oz-mode~ and then ~enter~. This will open the ~*Help*~ buffer (window) describing ~oz-mode~, which has a list of all relevant keybindings and links to more help pages (documentation). In Emacs, almost every mode, function and value is documented in this way. To see the different kinds of help you can get, type ~M-x describe~ and then ~tab~, which whill show you all of the ~describe~ functions. Of particular help are ~describe-symbol~ (~C-h o~) and ~describe-key~ (~C-h k~). ** Want to set up Oz in your Emacs environment? :PROPERTIES: :CUSTOM_ID: Want-to-set-up-Oz-in-your-Emacs-environment? :END: If you use Emacs outside of just using Oz, you may be annoyed that Oz is not set up when you launch Emacs without using the Oz launcher. Adding the below elisp code to your Emacs init file should solve that problem. This is taken from [[https://github.com/armkeh/setup/tree/master/emacs#other-programming-languages][my Emacs init]], where I explain what's going on. (It's not been tested on other machines, so YMMV). #+begin_src emacs-lisp (setq my-oz-home "/usr") (when (file-directory-p my-oz-home) (setenv "OZHOME" my-oz-home) ) (setq my-mozart-elisp "/usr/share/mozart/elisp") (when (file-directory-p my-mozart-elisp) (add-to-list 'load-path my-mozart-elisp) (load "mozart") (add-to-list 'auto-mode-alist '("\\.oz\\'" . oz-mode)) (add-to-list 'auto-mode-alist '("\\.ozg\\'" . oz-gump-mode)) (autoload 'run-oz "oz" "" t) (autoload 'oz-mode "oz" "" t) (autoload 'oz-gump-mode "oz" "" t) (autoload 'oz-new-buffer "oz" "" t) ) (eval-after-load "oz-mode" '(progn (define-key oz-mode-map (kbd "C-x SPC") 'rectangle-mark-mode) )) #+end_src ** Want to write literate Oz code in Org mode? :PROPERTIES: :CUSTOM_ID: Want-to-write-literate-Oz-code-in-Org-mode? :END: If you are using Org mode, you may wish to write literate Oz code in Org. Thankfully, support for evaluating Oz code blocks is built-in in Org. Simply add this to your init file. #+begin_src emacs-lisp (require 'ob-oz) #+end_src Then you write Oz code blocks like #+begin_src text #+begin_src oz :results output :tangle yes {Browse 'Hello world'} ,#+end_src #+end_src ~:results~ must be either ~output~ or ~result~. You probably also want the option ~:tangle yes~ to produce raw source files. To split your code up amongst several code blocks, you can use ~:noweb yes~. This lets you import other code blocks by their name. For example, #+begin_src text #+name: define-x #+begin_src oz :results output :noweb yes declare X = 2 ,#+end_src #+begin_src oz :results output :noweb yes <> {Browse X} ,#+end_src #+end_src #+RESULTS: * Tangle header :noexport: :PROPERTIES: :CUSTOM_ID: Tangle-header :END: #+begin_src oz :results output :tangle yes % This file is simply the “tangled” code of oz-demo.org; % it is the “raw” source code, provided for your convenience. #+end_src * Hello worlds :PROPERTIES: :CUSTOM_ID: Hello-worlds :END: Let's begin with the simplest hello world. Just display a sequence of characters. #+begin_src oz :results output :tangle yes {Browse 'Hello world'} #+end_src #+RESULTS: We can make it a bit more interesting with a (immutable) variable (i.e. a constant). We precede variable declarations with the ~declare~ keyword. #+begin_src oz :results output :tangle yes declare S = 'Hello world' {Browse S} #+end_src #+RESULTS: We can use arbitrary sequences of characters as names, surrounded by backticks. #+begin_src oz :results output :tangle yes declare `A fancier greeting` = 'A pleasure to make you acquaintance, my good fellow.' {Browse `A fancier greeting`} #+end_src #+RESULTS: * Some datatypes :PROPERTIES: :CUSTOM_ID: Some-datatypes :END: So far we've worked only with Oz's /atoms/ (not strings!). An atom may be: - A sequence of characters, numbers and underscores beginning with a lowercase letter. - Not a language keyword! - A sequence of printable characters enclosed in single quotes. - The body of the atom cannot include single quotes, for obvious reasons. #+begin_src oz :results output :tangle yes declare `An alphanumeric atom` = this_Is_An_Atom `A printable characters atom` = 'This is also an atom.' `A quoted keyword` = 'if' {Browse `An alphanumeric atom`} {Browse `A printable characters atom`} {Browse `A quoted keyword`} #+end_src #+RESULTS: Oz of course includes numeric datatypes #+begin_src oz :results output :tangle yes {Browse 123} % integer {Browse 1.23} % floating point {Browse &{ } % character ({ is 123 in ASCII) {Browse 0123} % octal (leading 0) {Browse 0x123} % hexidecimal (leading 0x) #+end_src #+RESULTS: Oz has booleans; ~true~ and ~false~ are not atoms, they are special, reserved names. (Reserved names actually form a type, which we may investigate later). #+begin_src oz :results output :tangle yes {Browse true} {Browse false} #+end_src #+RESULTS: Oz has lists, using a syntax similar to Prolog. - ~nil~ is the empty list. - ~|~ prepends a single element to a list; it is read “cons”. - brackets, ~[]~, are included as /syntactic sugar/. No commas! #+begin_src oz :results output :tangle yes {Browse nil} {Browse (1 | 2 | 3 | nil)} {Browse [1 2 3]} #+end_src #+RESULTS: Strings are lists of characters. #+begin_src oz :results output :tangle yes {Browse "Hello world"} {Browse [&H &e &l &l &o & &w &o &r &l &d]} {Browse ""} #+end_src #+RESULTS: Oz has /records/ for packing data together. #+begin_src oz :results output :tangle yes declare X = my_record_name( descr : 'A record carrying this string and an integer' a_num : 123) {Browse X} {Browse X.descr} {Browse X.a_num} #+end_src #+RESULTS: If you don't name fields, they're given numerical names. #+begin_src oz :results output :tangle yes declare X = r('I am field 1. Field 2 is 123. Field 3 is true.' 123 true) {Browse X.1} {Browse X.2} {Browse X.3} #+end_src #+RESULTS: Lists are implemented as records; ~1~ is the head and ~2~ is the tail. #+begin_src oz :results output :tangle yes declare L = [1 2 3] `Explicit L` = '|'(1 '|'(2 '|'(3 nil))) {Browse L.1} {Browse L.2} {Browse `Explicit L`} #+end_src #+RESULTS: * Control structures :PROPERTIES: :CUSTOM_ID: Control-structures :END: For now, we'll consider branching structures only. Loops are not much use until we have mutable state! Oz has ~if~ statements. #+begin_src oz :results output :tangle yes {Browse (if true then 'true is true.' end)} #+end_src #+RESULTS: There is an optional ~else~ clause. A runtime error will occur if it is needed and missing. #+begin_src oz :results output :tangle yes {Browse (if true then 'First branch' else 'Second branch' end)} #+end_src #+RESULTS: General rule: always include an ~else~ for expressions. It can be optional for statements. #+begin_src oz :results output :tangle yes if false then {Browse 'No else clause here.'} end #+end_src #+RESULTS: Oz also has the ~elseif~ syntactic sugar. #+begin_src oz :results output :tangle yes {Browse (if false then 'No.' elseif false then 'No.' else 'Yes.' end)} #+end_src #+RESULTS: And Oz includes a case statement for pattern matching. This is especially useful for working with lists! (Note that ~_~ indicates an anonymous variable). #+begin_src oz :results output :tangle yes declare L = [1 2 3] {Browse (case L of nil then 'Empty' [] _|nil then 'Singleton' [] _|_|nil then 'Length 2' [] _|_|_|nil then 'Length 3' else 'Longer than 3' end) } #+end_src #+RESULTS: * Comparisons :PROPERTIES: :CUSTOM_ID: Comparisons :END: Oz includes equality and other comparison operators. #+begin_src oz :results output :tangle yes {Browse 1 == 1} {Browse 1 =< 1} {Browse 1 >= 1} {Browse 1 < 1} {Browse 1 > 1} #+end_src #+RESULTS: They can be applied to other types. Most types have equality. #+begin_src oz :results output :tangle yes {Browse atom1 == atom2 } {Browse "String1" == "String2"} {Browse [1 2 3] == [1 2 3 4]} {Browse true == false } {Browse r(1 2 3) == r(2 3 4) } #+end_src #+RESULTS: Atoms are lexicographically ordered. #+begin_src oz :results output :tangle yes {Browse abc < bcd} {Browse abc < abcd} #+end_src #+RESULTS: Booleans, strings, lists and records are not ordered. #+begin_src oz :results output :tangle yes % {Browse [1] < [2]} % Cannot compare lists! #+end_src #+RESULTS: * Calling functions/procedures :PROPERTIES: :CUSTOM_ID: Calling-functions/procedures :END: Function/procedure calls are indicated with braces, as in ~{F x y ...}~. /Braces are not for grouping/; parentheses may be used for that. (Though parentheses are often not necessary). #+begin_src oz :results output :tangle yes {Browse {And false false}} {Browse {And false true }} {Browse {And true false}} {Browse {And true true }} #+end_src #+RESULTS: Note: we've been doing this all along with ~Browse~, a procedure! * Expressions and statements :PROPERTIES: :CUSTOM_ID: Expressions-and-statements :END: An /expression/ has a value, and not (necessarily) not a side effect. A /statement/ has a side effect, and not (necessarily) a value. So far, the only statement we have used is ~{Browse ...}~. Everything else has been an expression. In Oz, an expression cannot be used where a statement is expected, and vice versa. This gives an error: #+begin_src oz :results output :tangle yes %1 % Cannot “execute” an expression! #+end_src #+RESULTS: A /function/ is a subroutine which produces a value; therefore, a function invocation is an expression. A /procedure/ is a subroutine which produces a side effect; therefore, a procedure invocation is a statement. For now, let's focus on functions. * Defining functions Like with (immutable) variables, function declarations are preceded by a ~declare~ keyword. The syntax for a function declaration is ~fun {FunctionName Arg1 Arg2 ...} FunctionBody end~. ~FunctionBody~ must end with an expression, and its value will be the “return value”. #+begin_src oz :results output :tangle yes declare fun {Exp M N} if N == 0 then 1 else M * {Exp M (N - 1)} end end {Browse {Exp 2 5}} #+end_src #+RESULTS: Question; what is this, really? #+begin_src oz :results output :tangle yes declare fun {F} 5 end #+end_src #+RESULTS: The ~FunctionBody~ may involve statements (and so it can have side effects). After the statements must come an expression. #+begin_src oz :results output :tangle yes declare fun {F} {Browse 10} % do something 10 % return a value end #+end_src #+RESULTS: * Aside: currying :PROPERTIES: :CUSTOM_ID: Aside:-currying :END: The above ~Exp~ function is not curried; we cannot partially apply it. We can write a curried version using a /nested function definition/. We do not name the inner function (it is anonymous); we write ~$~ in place of a name. #+begin_src oz :results output :tangle yes declare fun {Exp M} fun {$ N} if N == 0 then 1 else M * {{Exp M} (N - 1)} end end end {Browse {{Exp 5} 5}} #+end_src #+RESULTS: A curried function has to be partially applied! * Aside: large numbers :PROPERTIES: :CUSTOM_ID: Aside:-large-numbers :END: Note that we have “infinite” precision arithmetic in Oz. It's limited only by the physical limit of our machines. #+begin_src oz :results output :tangle yes declare fun {Exp M N} if N == 0 then 1 else M * {Exp M (N - 1)} end end {Browse {Exp 5 5000}} #+end_src #+RESULTS: * Aside: mutual recursion :PROPERTIES: :CUSTOM_ID: Aside:-mutual-recursion :END: What if we want to define two functions which each depend upon the other? That's allowed! #+begin_src oz :results output :tangle yes declare fun {Step2 M} if M > 1 then {Step1 M - 2} else M end end fun {Step1 M} if M > 0 then {Step2 M - 1} else M end end fun {MyPlan M} {Step1 M} end #+end_src #+RESULTS: