diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..823468d --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +articulate-lisp.com \ No newline at end of file diff --git a/README.org b/README.org index b325d3a..0ac3e33 100644 --- a/README.org +++ b/README.org @@ -50,6 +50,8 @@ Each pull request is vetted to correctly compile in Jekyll; this is then logged on Github and has to pass for a pull request to be mergable to master. +We use [[https://github.com/orthecreedence/highlight-lisp][highlight-lisp]] for syntax highlighting. Just add a =lisp= class to +your code samples. ** Notes regarding build process. diff --git a/_includes/header.html b/_includes/header.html index 207ed6c..b47220e 100644 --- a/_includes/header.html +++ b/_includes/header.html @@ -9,6 +9,8 @@ + + @@ -44,6 +46,7 @@ {% endif %} {% endfor %} + @@ -51,3 +54,5 @@ + + diff --git a/_layouts/default.html b/_layouts/default.html index bcae0ea..12fe2ad 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -13,3 +13,7 @@ {% include footer.html %} + + diff --git a/css/highlight-lisp-github.css b/css/highlight-lisp-github.css new file mode 100644 index 0000000..e21fcab --- /dev/null +++ b/css/highlight-lisp-github.css @@ -0,0 +1,31 @@ +/** + * Inspired by github's default code highlighting + */ +pre { white-space: pre; background-color: #f8f8f8; border: 1px solid #ccc; font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-radius: 3px; } +pre code.hl-highlighted {white-space: pre; margin: 0; padding: 0; background: none; border: none; overflow-x: auto; font-size: 13px;} +code.hl-highlighted {margin: 0 2px; padding: 0 5px; white-space: nowrap; font-family: Consolas, "Liberation Mono", Courier, monospace; background: #f8f8f8; border: 1px solid #eaeaea; border-radius: 3px;} + +code.hl-highlighted {color: #008080;} +code.hl-highlighted .function {color: #008080;} +code.hl-highlighted .function.known {color: #800603;} +code.hl-highlighted .function.known.special {color: #2d2d2d; font-weight: bold;} +code.hl-highlighted .keyword {color: #990073;} +code.hl-highlighted .keyword.known {color: #990073;} +code.hl-highlighted .symbol {color: #75a;} +code.hl-highlighted .lambda-list {color: #966;} +code.hl-highlighted .number {color: #800;} +code.hl-highlighted .variable.known {color: #c3c;} +code.hl-highlighted .variable.global {color: #939;} +code.hl-highlighted .variable.constant {color: #229;} +code.hl-highlighted .nil {color: #f00;} +code.hl-highlighted .list {color: #222;} + +code.hl-highlighted .string, code.hl-highlighted .string * {color: #d14 !important;} +code.hl-highlighted .comment, +code.hl-highlighted .comment *, +code.hl-highlighted .comment .string +code.hl-highlighted .comment .string * {color: #aaa !important;} +code.hl-highlighted .string .comment {color: #d14 !important;} + +code.hl-highlighted .list.active {display: inline-block; background: #aefff7;} + diff --git a/examples/snippets.html b/examples/snippets.html index 046e369..0b4e957 100644 --- a/examples/snippets.html +++ b/examples/snippets.html @@ -7,107 +7,116 @@

Snippets

One of the great resources we can have as developers is snippets and example code to understand how the idiom of a language is spoken and written.

Defining a function:

-
(defun function-name (param1 param2 &key (keyword1 default-value))
-    ;; keywords are optional; optional positional parameters are also available. 
-    ;; implicit progn
-  )
+
(defun function-name (param1 param2 &key (keyword1 default-value))
+    ;; keywords are optional; optional positional parameters are also available.
+    ;; implicit progn
+)
+
+

Defining a method on a type:

-
(defmethod method-name ((param1 class-name))
-   ;; implicit progn
+
(defmethod method-name ((param1 class-name))
+  ;; implicit progn
   )
+

Defining a class

Note that DEFCLASS accessor functions for slots can be SETF’d and serve as both getters and setters for the slot.

:INITARG is the keyword used in MAKE-INSTANCE to denote the value of the initial argument (see below).

:INITFORM is the form used to initialize the slot. Without this, it defaults to nil. I favor using nil, 0, "", or (error "You must set slot <slotname> to a value") as the usual initform set.

Note that (:documentation ...) is the standard documentation mechanism, which can be viewed in the running image with DESCRIBE (at least in SBCL).

-

-;; no superclass, no slots.
-(defclass superclass-1 nil nil)
+

+;; no superclass, no slots.
+(defclass superclass-1 nil nil)
 
-(defclass my-class (superclass-1)
+(defclass my-class (superclass-1)
   ((variable
       :accessor accessor-function
       :initarg  :variable
       :initform form-for-initializition.)
    another-variable)
-  (:documentation "a class snippet!"))
+ (:documentation "a class snippet!"))
+

Creating an instance

-
(make-instance 'my-class :variable value)
+
(make-instance 'my-class :variable value)
+

Adding a constructor

This function runs after the instance is initialized.

-
(defmethod initialize-instance :after ((obj my-class) &key)
-  (setf (accessor-function obj) 10))
+
(defmethod initialize-instance :after ((obj my-class) &key)
+  (setf (accessor-function obj) 10))
+

Defining a constant:

Note that the convention is that constants are surrounded with +

-
(defconstant +name+ value "docstring")
+
(defconstant +name+ value "docstring")
+

Defining a global variable:

Note that the convention is that globals are surrounded with *

-
(defparameter *name* value "docstring")
+
(defparameter *name* value "docstring")
+

Creating local variables.

-
(let ((variable1 value-form)
+
(let ((variable1 value-form)
       (variable2 value-again))
-  ;; implicit progn where variable[12] are valid
+  ;; implicit progn where variable[12] are valid
    )
+

LOOP

LOOP is a contentious form in Common Lisp: some people love its imperative style, others hate it. Regardless, its really handy! Here are my favorite LOOPs


-(loop for i from 0 upto 10
+(loop for i from 0 upto 10
    collect i)
 
-(loop for i from 0 below 10
+(loop for i from 0 below 10
    collect i)
 
-(loop for i from 0 upto 10
-   do
+(loop for i from 0 upto 10
+   do
       (side-effect i))
 
-(loop for ele in list
+(loop for ele in list
    collect
       (operate-on ele))
 
-(loop for ele across array
+(loop for ele across array
    collect
       (operate-on ele))

Lambda functions

The lambda functions is an anonymous function, i.e., unnamed.

Here we map over numeric-list and increment each element in it by 1 with 1+, returning the incremented list.


-(mapcar
-   #'(lambda (x)
-       (1+ x))
+(mapcar
+   #'(lambda (x)
+       (1+ x))
    numeric-list)

Macro

Note that Lisp macros should be used with care: they read source code and emit source code.

-
(defmacro with-resource ((resource) &body body)
+
(defmacro with-resource ((resource) &body body)
    (allocate-resource ,resource)
-   (unwind-protect
-      (progn
+   (unwind-protect
+      (progn
          ,@body)
       (deallocate-resource ,resource)))

See UNWIND-PROTECT for details on this very useful form.

Writing a text file

More complete reading and writing of text files can be done by using the ALEXANDRIA library; these routines are great for starting to customize your own routine.

-
(defun write-file (filename data)
- (with-open-file (stream
+
(defun write-file (filename data)
+ (with-open-file (stream
                     filename
-                    :direction :output
-                    :if-exists :supersede
-                    :if-does-not-exist :create)
-    (write-sequence
+                    :direction :output
+                    :if-exists :supersede
+                    :if-does-not-exist :create)
+    (write-sequence
          data
-         stream)))
+ stream)))

Reading a text file


-(defun read-file (filename)
-  "Reads `filename` as a sequence of unsigned 8-bit bytes, no
-encoding"
-  (with-open-file (fin filename
-                   :direction :input
-                   :if-does-not-exist :error)
-    (let ((seq (make-array (file-length fin)
-                           :fill-pointer t)))
-      (setf (fill-pointer seq)
-            (read-sequence seq fin))
+(defun read-file (filename)
+  "Reads `filename` as a sequence of unsigned 8-bit bytes, no
+encoding"
+  (with-open-file (fin filename
+                   :direction :input
+                   :if-does-not-exist :error)
+    (let ((seq (make-array (file-length fin)
+                           :fill-pointer t)))
+      (setf (fill-pointer seq)
+            (read-sequence seq fin))
       seq)))

Please feel free to contribute your examples or library information to this page! Send in those pull requests and file those bugs!


diff --git a/examples/trotter.html b/examples/trotter.html index 0b444bc..3498854 100644 --- a/examples/trotter.html +++ b/examples/trotter.html @@ -14,50 +14,50 @@

Trotter Walkthrough

:babel))

DRAKMA is the standard HTTP(S) client library in Lisp, SPLIT-SEQUENCE does what you might think, CL-PPCRE is a reimplementation of the PPCRE library in native Lisp (It’s considered one of the best modern CL libraries, go check the source out sometime). BABEL is a encoding/decoding tool for strings. Note that they are referred to here as “keywords”.

The second form in the code defines a global that describes what an URL looks like. Of course, it’s not very precise, but it suffices for our purpose. The key thing here is that \ are doubled for the special forms. This is part of the CL-PPCRE regex definition.

-
(defparameter *url-regex* "(\\w+://[-\\w\\./_?=%&]+)"
-  "Hacked up regex suitable for demo purposes.")
+
(defparameter *url-regex* "(\\w+://[-\\w\\./_?=%&]+)"
+  "Hacked up regex suitable for demo purposes.")

Next, a predicate for HTTP. We really don’t care about FTP, HTTPS, GOPHER, GIT, etc protocols. It returns nil if it can’t find http:// in the URL.

-
(defun http-p (url)
-  (cl-ppcre:all-matches "\\bhttp://" url))
+
(defun http-p (url)
+  (cl-ppcre:all-matches "\\bhttp://" url))

Next, a predicate to check to see if our data is ASCII. While Common Lisp can handle Unicode data, this is a sample program, and the complexities of Unicode can be deferred.

-
(defun ascii-p (data)
-  "A not terribly great way to determine if the data is ASCII"
-  (unless (stringp data)
-    (loop for elem across data do
-         (when (> elem 127)
-           (return-from ascii-p nil))))
-  t)
+
(defun ascii-p (data)
+  "A not terribly great way to determine if the data is ASCII"
+  (unless (stringp data)
+    (loop for elem across data do
+         (when (> elem 127)
+           (return-from ascii-p nil))))
+  t)

Next, we have a quick (and dirty) way to see if a URL is going to point to a binary. It just looks for a binary file extension in the string.

-
(defun known-binary-p (url)
-    "Is this url a binary file?"
-    (let ((binaries
-              '(".png" ".bmp" ".jpg" ".exe" ".dmg" ".package" ".css"
-                   ".ico" ".gif" ".dtd" ".pdf" ".xml" ".tgz")))
-        (dolist (b binaries NIL)
-            (when (search b url)
-                (return T)))))
+
(defun known-binary-p (url)
+    "Is this url a binary file?"
+    (let ((binaries
+              '(".png" ".bmp" ".jpg" ".exe" ".dmg" ".package" ".css"
+                   ".ico" ".gif" ".dtd" ".pdf" ".xml" ".tgz")))
+        (dolist (b binaries NIL)
+            (when (search b url)
+                (return T)))))

The next form is the most complex: find-links.

find-links attempts to find all the links in a given url.


-(defun find-links (url)
-  "Scrapes links from a URL. Prints to STDOUT if an error is caught"
-  (when (and (http-p url)
-             (not (known-binary-p url)))
-    (handler-case
-        (let ((page (drakma:http-request url)))
-          (when page
-            (when (ascii-p page)
+(defun find-links (url)
+  "Scrapes links from a URL. Prints to STDOUT if an error is caught"
+  (when (and (http-p url)
+             (not (known-binary-p url)))
+    (handler-case
+        (let ((page (drakma:http-request url)))
+          (when page
+            (when (ascii-p page)
               (cl-ppcre:all-matches-as-strings
                *url-regex*
-               (if (stringp page)
+               (if (stringp page)
                    page
                    (babel:octets-to-string page))))))
 
-      #+sbcl(sb-int:simple-stream-error (se) (format t "Whoops, ~a didn't work. ~a~%" url se))
-      (DRAKMA::DRAKMA-SIMPLE-ERROR (se) (format t "Error? ~a threw ~a~%" url se))
-      (USOCKET:TIMEOUT-ERROR (se) (format t "timeout error ~a threw ~a~%" url se))
-      (USOCKET:NS-HOST-NOT-FOUND-ERROR (se) (format t "host-not-found error ~a threw ~a~%" url se))
-      (FLEXI-STREAMS:EXTERNAL-FORMAT-ENCODING-ERROR (se) (format t "~a threw ~a~%" url se)))))
+ #+sbcl(sb-int:simple-stream-error (se) (format t "Whoops, ~a didn't work. ~a~%" url se)) + (DRAKMA::DRAKMA-SIMPLE-ERROR (se) (format t "Error? ~a threw ~a~%" url se)) + (USOCKET:TIMEOUT-ERROR (se) (format t "timeout error ~a threw ~a~%" url se)) + (USOCKET:NS-HOST-NOT-FOUND-ERROR (se) (format t "host-not-found error ~a threw ~a~%" url se)) + (FLEXI-STREAMS:EXTERNAL-FORMAT-ENCODING-ERROR (se) (format t "~a threw ~a~%" url se)))))

The initial form is WHEN - a one-branch conditional. When we have a http link and it’s not a binary URL, then…

HANDLER-CASE wraps some code. HANDLER-CASE is part of the Common Lisp condition system; it serves as the “try” block in this situation. The list of errors below form the “catch” blocks. The interested reader is referred to the quicklinks section for more resources. Note that the errors are typical network errors- timeouts, stream errors, encoding errors.

The first form in HANDLER-CASE requests in the url and assigns it to page. Supposing we got something, we make sure it’s an ascii page; if so, we then find all the url-ish looking things, using the previously defined global. Supposing that the page is, indeed, a string, we return it, otherwise we convert the octets to a string and return that. N.b.: Common Lisp makes a difference between strings and vectors of bytes. Of course, if an error occurred, the HANDLER-CASE will route to the known conditions.

diff --git a/ides/emacs-setup.html b/ides/emacs-setup.html index 38aef3e..aa34e7e 100644 --- a/ides/emacs-setup.html +++ b/ides/emacs-setup.html @@ -5,15 +5,48 @@

Emacs

-

Emacs is the modern open source Lisp IDE. Its history and quirks extend back to the Lisp machines and early editors such as TECO.

-

It is considered difficult to initially learn, and often disparaged due to the antiquated interface, but is generally thought the best open source free IDE for Common Lisp.

-

In order to use emacs, there are two variants; XEmacs and GNU Emacs. I usually use GNU emacs, so I’ll talk about it here.

-

In order to get it, you can obtain it from the GNU. Windows, Linux, and OSX versions are available. It’s also available via most Linux distributions package repositories. The most recent version is 24; 23 is also recent and works well with the Superior Lisp Interaction Mode for Emacs, a.k.a SLIME.

-

New users can find many resources online for Emacs, including a well-written help system! An emacs tutorial can be found here, and the GNU FAQ is also available

+

Emacs is the modern open source Lisp IDE. Its history and +quirks extend back to the Lisp machines and early editors such as +TECO.

+ +

It is considered difficult to initially learn, and often disparaged +due to the antiquated interface, but is generally thought the best +open source free IDE for Common Lisp.

+ +

Get Emacs

+ +

With Portacle

+ +Portacle is a +portable and multiplatform Common Lisp development environment. It +packages SBCL, Emacs25, Slime, Quicklisp and Git altogether. There is no +installation required, so it's the easiest way to go. + +

Install GNU Emacs

+ +

In order to get it, you can obtain it from + its home page. Windows, +Linux, and OSX versions are available. It’s also available via +most Linux distributions package repositories. The most recent version +is 25; 23 still works well with the Superior Lisp +Interaction Mode for Emacs, a.k.a SLIME.

+ +

New users can find many resources online for Emacs, including a +well-written help system! An emacs tutorial + can be found here, +and the GNU Emacs FAQ is +also available.

+ +

Get SLIME

+

Usually you want to get SLIME installed for your development.

+

If you’re using emacs23, SLIME can be found here.

-

Emacs24 has it in its package manager (M-x package-list-packages).

+ +

Emacs24 and onwards has it in its package manager (M-x package-list-packages).

+

I like to use the following elisp to configure SLIME:

+
(require 'cl)
 (setq inferior-lisp-program  "/usr/local/bin/sbcl") ;modify to taste
 (require 'slime)
@@ -29,9 +62,22 @@ 

Emacs

(require 'paren) (show-paren-mode t)
+

Once you are set up…

-

When you load a Lisp file and want to engage SLIME, M-x slime will do the trick.

-

Paredit is a popular Lisp editing mode that the engaged student will hear about. The author recommends getting comfortable with emacs and SLIME before using Paredit, it provides several automatic s-expression editing features that surprised him on first use.

-

When you have configured your SLIME in a fancy fashion, you will find a SLIME REPL (Read Evaluate Print Loop) buffer created in your Emacs window.

-

This provides an interactive view into Common Lisp. You can evaluate functions you are writing in the source file and immediately use them in the REPL. This provides a very fast “code and test” facility.

-
+ +

When you load a Lisp file and want to engage SLIME, M-x + slime will do the trick.

+ +

Paredit is a popular Lisp editing mode that the engaged student +will hear about. The author recommends getting comfortable with emacs +and SLIME before using Paredit, it provides several automatic + s-expression editing features that surprised him on first use.

+ +

When you have configured your SLIME in a fancy +fashion, you will find a SLIME REPL (Read Evaluate Print Loop) buffer + created in your Emacs window.

+ +

This provides an interactive view into Common Lisp. You can +evaluate functions you are writing in the source file and immediately +use them in the REPL. This provides a very fast “code and +test” facility.


diff --git a/ides/summary.html b/ides/summary.html index 0aee9ff..9b673ed 100644 --- a/ides/summary.html +++ b/ides/summary.html @@ -8,11 +8,13 @@

IDE Selection

The canonical free IDE is undoubtably emacs, but it is difficult for newbies. The author has had good experience with messing around on LispWorks.

Open Source

Non-open source

Notes

CCL, in general, is very fast to load and has a good reputation for performance.


diff --git a/implementations/sbcl-setup.html b/implementations/sbcl-setup.html index 0221ba1..fcc6849 100644 --- a/implementations/sbcl-setup.html +++ b/implementations/sbcl-setup.html @@ -28,19 +28,22 @@

Installing on Linux and OSX

Linedit

The tool Linedit should provide some reasonable CLI capabilities for users.

In order to load it into SBCL, copy and paste the following snippet:

-
(progn
+
(progn
     (ql:quickload :linedit)
-    (require :sb-aclrepl)
-    (require :linedit)
-    (funcall (intern "INSTALL-REPL" :linedit) :wrap-current t))
+ (require :sb-aclrepl) + (require :linedit) + (funcall (intern "INSTALL-REPL" :linedit) :wrap-current t))

Installing on Windows

-

Dear Windows SBCL user, please tell us how it’s done!

+

Install the Scoop package manager. To do this, open PowerShell and type: ' iex (new-object net.webclient).downloadstring('https://get.scoop.sh') ' (minus single quotes). +Review the permissions for Scoop and and accept them if you are comfortable with them

+

Type: scoop install sbcl (no special permissions needed!) into PowerShell, and you're all set! Restart the shell and you can start working in SBCL!

+

Further installation on Linux/OSX

Sometimes the SBCL you pick up from sbcl.org isn’t as feature-complete as you want, or perhaps you want to recompile it for your own reasons (i.e., the Hunchentoot web server requires threads).

In order to do this, download the source SBCL package and issue this set of commands:

-
sh ./make.sh --fancy
-    pushd doc/manual/ && make && popd
-    sudo sh ./install.sh
+
sh ./make.sh --fancy
+    pushd doc/manual/ && make && popd
+    sudo sh ./install.sh