login  home  contents  what's new  discussion  bug reports     help  links  subscribe  changes  refresh  edit

Edit detail for LispInFriCAS revision 1 of 2

1 2
Editor: test1
Time: 2015/11/09 18:23:43 GMT+0
Note:

changed:
-
It is possible to enter Lisp expressions directly into FriCAS
(including function definitions) using the ')lisp' command,
but this is rather awkward for long Lisp programs.
\begin{axiom}
)lisp (defun foo1 (x y) (+ x y))
)lisp (foo1 2 3)
\end{axiom}

On the FriCAS wiki we can enter Lisp code in the same way that
we enter FriCAS code. For example::

  !\begin{lisp}
  (defun FOO2 (x y)
    (+ x y))
  \end{lisp}

The text between the !\begin{lisp} ... \end{lisp} is saved in a
temporary file (e.g. 'tempfile.lisp'). It is then compiled and
loaded into Lisp via the command::

  )lisp (load (compile-file "tempfile.lisp"))

\begin{lisp}
;;; Just a silly example
(defun FOO2 (x y)
  (+ x y))
\end{lisp}

Click '+lisp' to check the Lisp output for errors.

We can call the function from FriCAS like this:
\begin{axiom}
FOO2(3,4)$Lisp
\end{axiom}

Or we can call the function from Lisp like this:
\begin{lisp}
(format t "(FOO2 1 2) = ~a~%" (FOO2 1 2) )
\end{lisp}

Notice that the 'Value = T' is the result of the (load ...)
function call, not the value of the 'FOO2' function.

In the case of an error:
\begin{lisp}
(defunny FOO3 (x y)
  (+ x y))
\end{lisp}

'+lisp' shows the error message.

This is a lisp expression that generates some output.
\begin{lisp}
(format t "hello, world")
\end{lisp}

Lisp Tutorial 1

  http://www.cs.sfu.ca/CC/310/pwfong/Lisp/1/tutorial1.html

  Common LISP reads in an expression, evaluates it, and then
prints out the result. For example, if you want to compute the
value of '(2 * cos(0) * (4 + 6))', you type in:

\begin{axiom}
)lisp (* 2 (cos 0) (+ 4 6))
\end{axiom}

Here is a more complex recursive function.
\begin{lisp}
(defun fibonacci (N)
  "Compute the N'th Fibonacci number."
  (if (or (zerop N) (= N 1))
      1
    (+ (fibonacci (- N 1)) (fibonacci (- N 2)))))
\end{lisp}

We can trace its execution.
\begin{axiom}
)lisp (trace fibonacci)
)lisp (fibonacci 5)
\end{axiom}

Lisp specification:

   http://www.lispworks.com/documentation/HyperSpec/Front/

Lisp Links & Notes (advanced)

  http://www.cs.ucla.edu/classes/winter04/cs161/l1/lispLinks.html

  by Michael G. Dyer http://www.cs.ucla.edu/classes/winter04/cs161/l1

lambda, closures, apply, funcall, and mapcar

  One thing to note here is that the word "thunk" is often used as
a synonym for "closure".

A closure is defined as a double whose two elements are a pointer to
code and a pointer to an environment. In the adder example below, the
reason we need the "environment pointer" is that we need a way to
remember what n was bound to at the time that (adder 3) was created.

This particular "adder" example comes from the
"CL Cookbook":http://cl-cookbook.sourceforge.net

\begin{lisp}
(defun adder (n)
   (function (lambda (x) (+ x n)))
)
\end{lisp}

\begin{axiom}
)lisp (adder 3)
)lisp (apply (adder 3) '(4))
)lisp (funcall (adder 3) 4)
)lisp (mapcar (adder 3) '(1 2 3 4))
\end{axiom}

There are two slightly different ways of using mapcar. One
is by passing it a lambda block, which is created by simply
prepending the #' in front of the function name. The other
is to pass it a closure:

\begin{lisp}
(defun increment (i)
   (+ i 1)
)
\end{lisp}

\begin{axiom}
)lisp #'increment
)lisp (mapcar #'increment '(1 2 3))
)lisp #'(lambda (x) (increment x))
)lisp (mapcar #'(lambda (x) (increment x)) '(1 2 3))
\end{axiom}

compose

  Let's take a look at a "higher-order" function, which means
that it takes functions as arguments. The compose function is
the same as in mathematics. f(g(x)) = compose(f,g)(x)

\begin{lisp}
(defun increment (i)
  (+ i 1)
)

(defun square (z)
  (* z z)
)

(defun compose (f g)
   #'(lambda (x) (funcall f (funcall g x)))
)
\end{lisp}

\begin{axiom}
)lisp (funcall (compose #'increment #'square) 3)
\end{axiom}

curry and uncurry

\begin{lisp}
(defun printthree (arg1 arg2 arg3)
  (format *query-io* "arg1 = ~A, arg2 = ~A, arg3 = ~A~%" arg1 arg2 arg3)
)
\end{lisp}

\begin{axiom}
)lisp (printthree 3 4 4) 
\end{axiom}

\begin{lisp}
(defun curry (function &rest args)
  (function (lambda (&rest more-args)
   (apply function (append args more-args)))))
\end{lisp}


\begin{axiom}
)lisp (curry #'printthree 'a)
)lisp (apply (curry #'printthree 'a) '(b c))
)lisp (curry #'printthree 'a 'b)
)lisp (apply (curry #'printthree 'a 'b) '(c))
\end{axiom}

\begin{lisp}
(defun uncurry (f)
   #'(lambda (x y)  (funcall (funcall f x) y))
)

(defun uncurry (f)
   #'(lambda (x y)  (funcall (funcall f x) y))
)
\end{lisp}

\begin{axiom}
)lisp (uncurry (curry #'+ 1))
\end{axiom}

It is possible to enter Lisp expressions directly into FriCAS? (including function definitions) using the )lisp command, but this is rather awkward for long Lisp programs.

fricas
)lisp (defun foo1 (x y) (+ x y))
Value = FOO1
fricas
)lisp (foo1 2 3)
Value = 5

On the FriCAS? wiki we can enter Lisp code in the same way that we enter FriCAS? code. For example:

  \begin{lisp}
  (defun FOO2 (x y)
    (+ x y))
  \end{lisp}

The text between the \begin{lisp} ... \end{lisp} is saved in a temporary file (e.g. tempfile.lisp). It is then compiled and loaded into Lisp via the command:

  )lisp (load (compile-file "tempfile.lisp"))

lisp
;;; Just a silly example
(defun FOO2 (x y)
  (+ x y))
lisp
; compiling file "/var/aw/var/LatexWiki/5467520105124776552-25px002.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/5467520105124776552-25px002.fasl written ; compilation finished in 0:00:00.003 Value = T

Click +lisp to check the Lisp output for errors.

We can call the function from FriCAS? like this:

fricas
FOO2(3,4)$Lisp

\label{eq1}7(1)
Type: SExpression?

Or we can call the function from Lisp like this:

lisp
(format t "(FOO2 1 2) = ~a~%" (FOO2 1 2) )
lisp
; compiling file "/var/aw/var/LatexWiki/4849575266889566101-25px004.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/4849575266889566101-25px004.fasl written ; compilation finished in 0:00:00.000 (FOO2 1 2) = 3 Value = T

Notice that the Value = T is the result of the (load ...) function call, not the value of the FOO2 function.

In the case of an error:

lisp
(defunny FOO3 (x y)
  (+ x y))
lisp
; compiling file "/var/aw/var/LatexWiki/7691373298349222252-25px005.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/7691373298349222252-25px005.fasl written ; compilation finished in 0:00:00.001
>> System error: The variable FOO3 is unbound.

+lisp shows the error message.

This is a lisp expression that generates some output.

lisp
(format t "hello, world")
lisp
; compiling file "/var/aw/var/LatexWiki/229055943891593707-25px006.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/229055943891593707-25px006.fasl written ; compilation finished in 0:00:00.001 hello, world Value = T

Lisp Tutorial 1

http://www.cs.sfu.ca/CC/310/pwfong/Lisp/1/tutorial1.html

Common LISP reads in an expression, evaluates it, and then prints out the result. For example, if you want to compute the value of (2 * cos(0) * (4 + 6)), you type in:

fricas
)lisp (* 2 (cos 0) (+ 4 6))
Value = 20.0f0

Here is a more complex recursive function.

lisp
(defun fibonacci (N)
  "Compute the N'th Fibonacci number."
  (if (or (zerop N) (= N 1))
      1
    (+ (fibonacci (- N 1)) (fibonacci (- N 2)))))
lisp
; compiling file "/var/aw/var/LatexWiki/8805225188305955522-25px008.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/8805225188305955522-25px008.fasl written ; compilation finished in 0:00:00.003 Value = T

We can trace its execution.

fricas
)lisp (trace fibonacci)
Value = (FIBONACCI)
fricas
)lisp (fibonacci 5)
0: (FIBONACCI 5) 1: (FIBONACCI 4) 2: (FIBONACCI 3) 3: (FIBONACCI 2) 4: (FIBONACCI 1) 4: FIBONACCI returned 1 4: (FIBONACCI 0) 4: FIBONACCI returned 1 3: FIBONACCI returned 2 3: (FIBONACCI 1) 3: FIBONACCI returned 1 2: FIBONACCI returned 3 2: (FIBONACCI 2) 3: (FIBONACCI 1) 3: FIBONACCI returned 1 3: (FIBONACCI 0) 3: FIBONACCI returned 1 2: FIBONACCI returned 2 1: FIBONACCI returned 5 1: (FIBONACCI 3) 2: (FIBONACCI 2) 3: (FIBONACCI 1) 3: FIBONACCI returned 1 3: (FIBONACCI 0) 3: FIBONACCI returned 1 2: FIBONACCI returned 2 2: (FIBONACCI 1) 2: FIBONACCI returned 1 1: FIBONACCI returned 3 0: FIBONACCI returned 8 Value = 8

Lisp specification:

http://www.lispworks.com/documentation/HyperSpec/Front/

Lisp Links & Notes (advanced)

http://www.cs.ucla.edu/classes/winter04/cs161/l1/lispLinks.html

by Michael G. Dyer http://www.cs.ucla.edu/classes/winter04/cs161/l1

lambda, closures, apply, funcall, and mapcar

One thing to note here is that the word "thunk" is often used as a synonym for "closure".

A closure is defined as a double whose two elements are a pointer to code and a pointer to an environment. In the adder example below, the reason we need the "environment pointer" is that we need a way to remember what n was bound to at the time that (adder 3) was created.

This particular "adder" example comes from the CL Cookbook

lisp
(defun adder (n)
   (function (lambda (x) (+ x n)))
)
lisp
; compiling file "/var/aw/var/LatexWiki/1662804482358068841-25px010.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/1662804482358068841-25px010.fasl written ; compilation finished in 0:00:00.002 Value = T

fricas
)lisp (adder 3)
Value = #<CLOSURE (LAMBDA (X) :IN ADDER) {10049D960B}>
fricas
)lisp (apply (adder 3) '(4))
Value = 7
fricas
)lisp (funcall (adder 3) 4)
Value = 7
fricas
)lisp (mapcar (adder 3) '(1 2 3 4))
Value = (4 5 6 7)

There are two slightly different ways of using mapcar. One is by passing it a lambda block, which is created by simply prepending the #' in front of the function name. The other is to pass it a closure:

lisp
(defun increment (i)
   (+ i 1)
)
lisp
; compiling file "/var/aw/var/LatexWiki/4211409212481666063-25px012.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/4211409212481666063-25px012.fasl written ; compilation finished in 0:00:00.001 Value = T

fricas
)lisp #'increment
Value = #<FUNCTION INCREMENT>
fricas
)lisp (mapcar #'increment '(1 2 3))
Value = (2 3 4)
fricas
)lisp #'(lambda (x) (increment x))
Value = #<INTERPRETED-FUNCTION NIL {1004A3CBEB}>
fricas
)lisp (mapcar #'(lambda (x) (increment x)) '(1 2 3))
Value = (2 3 4)

compose

Let's take a look at a "higher-order" function, which means that it takes functions as arguments. The compose function is the same as in mathematics. f(g(x)) = compose(f,g)(x)

lisp
(defun increment (i)
  (+ i 1)
)
(defun square (z) (* z z) )
(defun compose (f g) #'(lambda (x) (funcall f (funcall g x))) )
lisp
; compiling file "/var/aw/var/LatexWiki/6034342207465796072-25px014.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/6034342207465796072-25px014.fasl written ; compilation finished in 0:00:00.010 Value = T

fricas
)lisp (funcall (compose #'increment #'square) 3)
Value = 10

curry and uncurry

lisp
(defun printthree (arg1 arg2 arg3)
  (format *query-io* "arg1 = ~A, arg2 = ~A, arg3 = ~A~%" arg1 arg2 arg3)
)
lisp
; compiling file "/var/aw/var/LatexWiki/4952192325462136804-25px016.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/4952192325462136804-25px016.fasl written ; compilation finished in 0:00:00.010 Value = T

fricas
)lisp (printthree 3 4 4)
arg1 = 3, arg2 = 4, arg3 = 4 Value = NIL

lisp
(defun curry (function &rest args)
  (function (lambda (&rest more-args)
   (apply function (append args more-args)))))
lisp
; compiling file "/var/aw/var/LatexWiki/2878124551976497830-25px018.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/2878124551976497830-25px018.fasl written ; compilation finished in 0:00:00.003 Value = T

fricas
)lisp (curry #'printthree 'a)
Value = #<CLOSURE (LAMBDA (&REST MORE-ARGS) :IN CURRY) {1004C109BB}>
fricas
)lisp (apply (curry #'printthree 'a) '(b c))
arg1 = A, arg2 = B, arg3 = C Value = NIL
fricas
)lisp (curry #'printthree 'a 'b)
Value = #<CLOSURE (LAMBDA (&REST MORE-ARGS) :IN CURRY) {1004C17C0B}>
fricas
)lisp (apply (curry #'printthree 'a 'b) '(c))
arg1 = A, arg2 = B, arg3 = C Value = NIL

lisp
(defun uncurry (f)
   #'(lambda (x y)  (funcall (funcall f x) y))
)
(defun uncurry (f) #'(lambda (x y) (funcall (funcall f x) y)) )
lisp
; compiling file "/var/aw/var/LatexWiki/6522788210180720678-25px020.lisp" (written 07 MAY 2016 12:54:25 PM):
; /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/6522788210180720678-25px020.fasl written ; compilation finished in 0:00:00.007 Value = T

fricas
)lisp (uncurry (curry #'+ 1))
Value = #<CLOSURE (LAMBDA (X Y) :IN UNCURRY) {1004CBF18B}>