God writes in Lisp

A few interesting books, from easy to difficult,
-Common lisp, a gentle introduction to symbolic computing
-Successful lisp
-Praise for practical common lisp
-ANSI Common lisp
-Let over lambda
-Onlisp
-The Common Lisp Cookbook
 
Last edited:
"ANSI Common Lisp" and "On Lisp" are both by the same author. "On Lisp" (mostly about metaprogramming) is free (no cost) now. Not sure about ANSI Common Lisp.
"ANSI CL" is an introductory book, a very good one. "On Lisp" is not introductory, I would say, it is not wise to start "On Lisp" without having mastered the content of "ANSI CL" (or equivalent book). About "free of cost", It does not really matter to me, for a good book i am ready to pay. (we all know where to find the "free" pdf version to read in the ipad before buying the paper;) ).
 
After reading some of the lisp sources, I would say god writes directly in binary, self modifying and sprinkeled with some quantum foam.

Much of the code that has been shown here is CLOS, the object-oriented extension to Common Lisp which is pretty verbose. Not my favorite.

It is worth noting that the object-oriented extensions can be implemented purely in macros without compiler changes from non-OO Common Lisp, just with compile-time computing. Think about implementing C++ in C using just C macros, not having to change the compiler at all.
 
If you're interested in the semantics and implementation of the Lisp family of languages, Queinnec's "Lisp In Small Pieces" is very much worth reading, perhaps too detailed for today's attention deficit disordered world! It describes 11 interpreters and 2 compilers!
 
A few interesting books, from easy to difficult,
-Common lisp, a gentle introduction to symbolic computing
-Successful lisp
-Praise for practical common lisp
-ANSI Common lisp
-Let over lambda
. I know (1) and (4) i can add/reccomend, at least to see, these:
. Common Lisp The Language v2. [I spent many hours on that, if was probably the first real programming language manual i red]
. The HyperSpec [ ANSI version of the previous, super cool reference ]
. SICP . [ really a Scheme book, but a wonderful one]
. The Little Schemer [ again, Scheme, but still a very nice book ]
. PAIP. [ IMO it is too big to be loved, I red a few chapters, but it was very popoular ]
. Object Oriented Common Lips [ an easy book, a nice book ]
. The Lisp 1.5 manual, this has to be seen
. It makes a lot of sense to read a bit of Emacs Lisp. Just to understand how things can be different from Common Lisp. And how to use Lisp as a scripting language.
.... I remember a brown book, little, i liked it, i don't have it around, if i find i will post
(*) there are meny others i bought but i had never occasion to read: The art of MOP, Practical Common Lisp, An orange and black one, from a french guy i think, that is more abstract, more research ... bye
 
Small differences between racket-scheme & sbcl-lisp.

A counter in scheme :
Code:
#lang typed/racket

(: my-counter! ( -> () Number))
(define my-counter!
    (let ([t 0])
        (lambda ()
            (set! t (+ 1 t))
        t)))
(print (my-counter!))
(print (my-counter!))

A counter in sbcl lisp:
Code:
(load "~/quicklisp/setup.lisp")
(declaim (optimize (speed 3) (safety 3) (space 0) (debug 3)))

(ql:quickload "serapeum")

(defpackage mypack
  (:use :cl :serapeum)
  (:export main));defpackage

(in-package :mypack)

(let ((c 0))
    (-> my-counter! () (-> () integer) )
    (defun my-counter! ()
        #'(lambda ()
            (setf c (+ 1 c))
        c))) ;let

(defun main ()
    (print (funcall (my-counter!)))
    (print (funcall (my-counter!))))


(in-package :cl)
(defun main ()
  (mypack::main))
(sb-ext:save-lisp-and-die "test.exe" :toplevel #'main :executable t)
 
Last edited:
A hello world lisp program with full static type checking,

Code:
(load "~/quicklisp/setup.lisp")
(declaim (optimize (speed 3) (safety 3) (space 0) (debug 3)))
(ql:quickload "serapeum")
(ql:quickload "fiasco")
(ql:quickload "coalton")
(ql:quickload "postmodern")

(defpackage mymain
  (:use #:cl
        #:serapeum)
  (:export main)) ;defpackage

(defpackage mycoalton
  (:use #:coalton 
        #:coalton-prelude)
  (:local-nicknames (#:co #:cl) (#:pm #:postmodern))
  (:export cmain) ) ;defpackage

(in-package :mycoalton)
(coalton-toplevel
    (declare myconnect ( Unit -> Unit ))
    (define (myconnect)
        (Lisp Unit()
            (pm:connect-toplevel "x" "x" "x" "127.0.0.1" :port 5432 ) 
            Unit))
    (declare myquery ( Unit -> String ))
    (define (myquery)
        (Lisp String()
            (co:let ((myname nil)
                       (myage  nil)
                       (mysum  nil))
                (pm:doquery (:select 'name 'age :from 'persons)
                    (myname myage)
                    (co:setf mysum (co:concatenate co::'string mysum (co:format nil "~a:~a ~%" myname myage))))
                mysum)))
    (declare cmain ( Unit -> Unit ))
    (define (cmain)
        (myconnect)
        (Lisp Unit()
            (co:format co:t "~a ~%" (myquery Unit))
            Unit) 
        Unit)) ;toplevel

(in-package :mymain)
(-> main () Integer )
(defun main ()
    (mycoalton:cmain coalton:Unit)
    0 ) ; main
(sb-ext:save-lisp-and-die "test.exe" :toplevel #'main :executable t)
 
A hello world lisp program with full static type checking,
Code:
(load "~/quicklisp/setup.lisp")

(declaim (optimize (speed 3) (safety 3) (space 0) (debug 3)))

(ql:quickload "serapeum")
(ql:quickload "fiasco")
(ql:quickload "coalton")

(defpackage mymain
  (:use #:cl
        #:serapeum)
  (:export main));defpackage

(defpackage mycoalton
  (:use #:coalton
        #:coalton-prelude)
  (:local-nicknames (#:mycl #:cl))
  (:export cmain) );defpackage

(in-package :mycoalton)

(coalton-toplevel
    (declare ctext String)
    (define  ctext "Hello World")

    (declare myprint ( String -> Unit ))
    (define (myprint s)
        (Lisp Unit (s) (mycl:princ s) Unit)
        );define

    (declare cmain ( Unit -> Unit ))
    (define (cmain) (myprint ctext))
    );toplevel

(in-package :mymain)
(-> main () Integer )
(defun main ()
        (mycoalton:cmain coalton:Unit)
        0
        )
(sb-ext:save-lisp-and-die "test.exe" :toplevel #'main :executable t)

A few remarks:
  • This is using an extensive package for type-checking. I am not convinced that I like syntax chosen a lot.
  • This package, and many like it, have been implemented as a library. The compiler has not been changed in any way. Try that in Python.
  • In SBCL you get useful warnings without using such a package for type errors: https://medium.com/@MartinCracauer/...mmable-programming-language-lisp-79bb79eb068a
  • The indenting style with closing parenthesis on their own lines is frowned upon. Generally the indentation alone should make it obvious where each block is scoped. A proper indentation mode in e.g. Emacs will have various spacings to help here.
 
Edited post #61
Typed languages like Haskell & F# & Ocaml also have sometimes a "weird" syntax.
Also CLOS is "verbose" but powerful.
The "wrapping" needed by coalton is "annoying".
As editors i'll try neovim & vscode.

A CLOS test using sbcl,
Code:
(load "~/quicklisp/setup.lisp")
(declaim (optimize (speed 3) (safety 3) (space 0) (debug 3)))
(ql:quickload "serapeum")
(defpackage mypack
  (:use :cl :serapeum)
  (:export main));defpackage
(in-package :mypack)

(defclass bank-account ()
    (customer-name balance))
(defgeneric balance (dummy))
(defgeneric customer-name (dummy))

(-> customer-name (bank-account) String)
(defmethod customer-name ((account bank-account))
    (slot-value account 'customer-name))
(-> balance (bank-account) Integer)
(defmethod balance ((account bank-account))
    (slot-value account 'balance))
(-> (setf customer-name) (String bank-account) nil)
(defmethod (setf customer-name) (aname account)
    (setf ( slot-value account 'customer-name ) aname))
(-> (setf balance) (Integer bank-account) nil)
(defmethod (setf balance) (abal account)
    (setf ( slot-value account 'balance ) abal))

(defparameter *account* (make-instance 'bank-account))
(-> main () integer )
(defun main ()
    (setf (customer-name *account*) "Alain")
    (setf (balance *account*) 100)
    (print (customer-name *account*))
    (print (balance *account*))
    0)
(in-package :cl)
(defun main ()
  (mypack::main)
   0 )
(sb-ext:save-lisp-and-die "test.exe" :toplevel #'main :executable t)
 
Last edited:
Code:
#include <iostream>
static int counter(void) {
  static int c=0;
  return c++;
}
void main(void){
  std::cout << counter() << " " << counter() ;
}

.. just for comparison
 
Code:
#include <iostream>
static int counter(void) {
  static int c=0;
  return c++;
}
void main(void){
  std::cout << counter() << " " << counter() ;
}

.. just for comparison
That’s only one counter. In Scheme/lisp you can have multiple independent counters. For example,
Code:
(define (counter n)
  (lambda () (let ((r n)) (set! n (+ n 1)) r)))
(define c1 (counter 5))
(define c2 (counter 42))
(c1) ; returns 5
(c1) ; returns 6
(c2) ; returns 42
(c2) ; returns 43
Now c1 will count up from 5, c2 will count up from 42. You can simulate this in C++ with a Counter class but that is much uglier. Of course, nowadays most modern languages provide closures. See for example https://go.dev/play/p/8Q3cNOJKmAW
 
A kawa swing GUI application,

Code:
;; -*- coding:utf-8; mode:Scheme -*-

(define-alias JLabel javax.swing.JLabel)
(define-alias JButton javax.swing.JButton)

(define-simple-class SimpleFrame (javax.swing.JFrame)
    (label ::JLabel allocation: 'instance  access: 'private 
        init: (JLabel "Kawa Swing Application"))
    (button allocation: 'instance  access: 'private 
        init: (JButton "Click Me"
                action-listener: (lambda (event)(on-click-btn))))
    ((*init*) ;; constructor
    (invoke-special javax.swing.JFrame (this) 
        '*init* "Hola Swing desde Kawa")
    (format #t "Initialising ...~%")
    (add label java.awt.BorderLayout:CENTER)
    (add button java.awt.BorderLayout:SOUTH)
    (setDefaultCloseOperation javax.swing.JFrame:EXIT_ON_CLOSE)
    (pack))
    ((on-click-btn) allocation: 'instance  access: 'protected
    (label:setText "You clicked!")))

(define (main)
  (let ((frame (SimpleFrame)))
    (frame:setVisible #t)))

(main)

To run,
Code:
java -jar ./kawa.jar -f ./test.scm  -Dkawa.import.path="/usr/local/share/slib"
 
Back
Top