Guile is a scheme based lisp that is intended to be the universal GNU extension language. It is designed to inter-operate with C code very easily (though I wish it could do the same with Rust code), and it supports programming in other languages (javascript, emacs-lisp, and hopefully someday many others). Guile has a module based system, threads, full access to POSIX calls, dynamic linking, networking support, string processing, a foreign function call interface (let's Guile run a function from a different language), etc.
When emacs-lisp became so popular in extending Emacs, some of the leaders of the GNU project, wanted to make an official lisp language that all others GNU packages could use as an extension language. Currently only a few Emacs packages use Guile as an extension language, but hopefully someday many more will. In fact, perhaps in a few years, the default Emacs package will probably run on the Guile vm (running emacs lisp code), which will make the default Emacs experience that much faster!
Scheme, like most lisps, has a very limited syntax. This is actually a valuable language feature, because it makes the language easy to learn. The two main things to learn are the following:
(operator operand1 operand2 operand3 ...)
The first word in a parenthesis in guile, is a command. The following words are arguments to the command. For example,
(+ 5 3)
evaluates to 8. This calculation commands can even be nested in complicated ways like
#+BEGIN_SRC scheme (+ 5 (* 3 (- 8 3 (- 10 9)) (/ 10 2)) (+ 8 9 10)) #+END_SRC
which can be rearranged to be so that humans can understand how to compute this odd arbitrary expression.
#+BEGIN_SRC scheme (+ 5 (* 3 (- 8 3 (- 10 9)) (/ 10 2)) (+ 8 9 10)) #+END_SRC
This set up is quite nice. If you align the operands vertically it gives one a good understanding up what is happening.
Scheme is latent-ly typed. This is like dynamic typing, which is like python. A variable does not have to have an associated type with it. The following python code demonstrates this. The variable a
can change between a string or a number depending on what is assigned to it.
a = 5
print (a)
a = "hello"
print (a)
5 hello
Defining variables in scheme is easy too.
#+BEGIN_SRC scheme (define color blue) #+END_SRC
To change a variable's value, one does
#+BEGIN_SRC scheme (set! x blue) #+END_SRC
In scheme #t
and #f
are the booleans true and false.
You can also easily define functions
(define *3 (lambda (x) (* x 3)))
You can also write it like:
(define (*3 x) (* x 3))
Scheme is a dialect of lisp, which stands for list processing. A list is just a bunch of linked cons cells. A cons cell is a constructor that makes lists. A cons cell contains two element. The first element is called the car, and the second is called tho cdr (could-er). These are cons cells.
(cons 1 2)
(1 . 2)
'(1 2)
1 | 2 |
(cons 1 '())
(1)
To make a list, you build up a ton of cons cells:
(cons 5 (cons 2 (cons 6 (cons 1 '()))))
(5 2 6 1)
You can also make a list like this:
'(5 . (2 . (4 . ( 8 . ()))))
(5 2 4 8)
Since scheme processes lists, you can write a plus operation as a list.
(+ . (5 . (2 . ())))
7
There are also some things that look like procedures, but are actually special syntax. A good example is the "if" syntax.
(if (string=? (read-answer "should I copy this file")
"yes")
(copy-file "/path/to/file.scm")
(print "Fine I won't copy the file."))
If "if" was a procedure, then copy-file and string=? would be evaluated, then given to if as arguments. BUT that's not what happens. Instead, if acts in a different way. Namely if TEST THEN ELSE. If TEST returns true, then the THEN is executed. Otherwise the ELSE is executed.
The first word after the parenthesis is the procedure and the other words are it's arguments.
(+ 2 3)
5
But you can quote something and it just returns data
'(+ 2 3)
(+ 2 3)
You can also quote things and quasi-quote in the middle.
`(+ 2 ,(* 2 4))
(+ 2 8)
You can also unquote slicing!
(define x '(2 3))
`(1 ,x 4)
1 | (2 3) | 4 |
(define x '(2 3))
`(1 ,@x 4)
1 | 2 | 3 | 4 |
(define x '(2 3))
`(1 (+ ,@x) 4)
1 | (+ 2 3) | 4 |
Closures are a bit like static variables in C. It is a way to make a function being called repeatedly remember the value of the variables instead of resetting them. ie:
(let loop ((number 0))
(lambda ()
(unless (> number 10)
(set! number (+ 1 number))
(display "Number is ")
(display number)
(display "\n")
(loop number))))
#:6:2 ()>
This is an atom
atom
(atom)
So is this
stnahuntsuhntahouetnhsn34thu
So is this
23435345
I'm not an atom, I'm a list
'()
()
Guile doesn't have the standard scheme procedure to check for atoms: "atom?". Let's write one!
(define atom?
(lambda (a)
(if (list? a)
#f
#t)))
All atoms are S-expressions
This is an S-expression
atom
A list is a set of S expressions enclosed by parenthesis
'(I'm a list)
(I'm a list)
I'm a list
'()
Null returns true if it's parameter is an empty list.
(null? '())
#t
(null? 0)
#f
(null? "")
#f
Get the first item in the list
(car '(a b c d))
a
(car '((hello dog) ((Yup this is cool)) 5 o e))
(hello dog)
(car (quote (a b c d)))
a
Car is only defined for non-empty lists.
(car '())
"An error occurred."
cdr is pronounced "could-er". cdr is the list without the first item.
(cdr '(a b c d))
(b c d)
(cdr '(((vegan hot dog)) bc d (5 4 3)))
(bc d (5 4 3))
(cdr (quote (a b c d)))
(b c d)
cdr is defined for non-empty lists.
(cdr '())
"An error occurred."
eq? takes two arguments and each must be a non-numeric atom or a list.
(eq? 5 5)
#t
(eq? (car (quote (a b c))) (quote a))
#t
The above can be written like
(eq? (car '(a b c)) 'a)
#t
(eq? (cdr '(a b c d)) '(b c d))
#t
lat? asks is the list is made up of only atoms. Guile doesn't have it apparently.
<<atom>>
(define lat?
(lambda (l)
(cond
;; is l '() ?
((null? l) #t)
;; is the first item in the list an atom?
((atom? (car l) (lat? (cdr l))))
;; if (car l) is not an item, then return false.
(else #f))))
#
<<lat>>
(display (lat? '(a b c d e)))
cons stands for constructor. It constructs lists. This first example is an improper list. Operations like map and filter will not work on them.
(cons '1 '2)
(1 . 2)
(cons '1 (cons '2 '()))
(1 2)
(cons '1 (cons '2 (cons '3 (cons '4 (cons '5 '())))))
(1 2 3 4 5)
You can also just use list, which is much easier.
(list 1 2 3 4 5)
(1 2 3 4 5)
Let's define an abs function or absolute value function
(define (abs x)
(cond
((> x 0) x)
((< x 0) (- x))
((= x 0) 0)))
There is a simpler solution though. If x is greater than 0, return x. Otherwise return -x.
(define (abs x)
(cond
((> x 0) x)
(else (- x))))
Scheme does not provide a for loop. Instead it forces you to write recursive functions (which normally look better than for loops). Most schemes then compile/interpret those recursive calls into for loops internally anyway. This is called tail call optimization.
(define (print1-10 x)
(unless (= x 11)
(display x)
(display " ")
(print1-10 (+ x 1))))
(print1-10 1)
This can be done a little better though. You can used a named let. It names a function and then calls it.
(let loop ((x 1))
(unless (= x 11)
(display x) (display " ")
(loop (+ 1 x))))
This is the same as
(define loop (lambda (x 1)
(unless (= x 11)
(display x)
(display " ")
(loop (+ 1 x)))))
(loop)
Apparently, scheme treats [] the same as ().
This can be useful in let expressions to make them easier to read.
(let ([n 5] [b 4]) (+ n b))
9
Check this out, you can store procedures in a let variable:
(let ([a +]) (a 1 2 3))
6
Scheme functions are called procedures, because scheme is based on lambda calculus. Often times procedures are created using a lambda expression.
(lambda (x y z)
(+ x y z))
Here is what is really cool! You can create a lambda function and immediately pass it arguments. This is like an anonymous function in javascript.
((lambda (x y z)
(+ x y z))
1 2 3)
6
(let ((a 1) (b 2)) (+ a b))
(let* binds the variable values sequentially.
Suppose you have a let like so:
(let ((a 1) (b (+ 1 a))) (+ a b))
"An error occurred."
The error occurs because scheme tries to define both a & b at the same time! This won't work, because b can only be defined after a has a value. So instead, you must use let*
(let* ((a 1) (b (+ 1 a))) (+ a b))
3
(letrec ((even? (lambda (n)
(if (zero? n)
#t
(odd? (- n 1)))))
(odd? (lambda (n)
(if (zero? n)
#f
(even? (- n 1))))))
(even? 88))
A closure is an environment with the local variables and a reference to the higher environment, which contains a reference to all of the higher environments' variables. One create a new sub-environment, when one uses a lambda. The previous environment is saved between calls. This is called a closure.
(define make-counter ()
(let ((current-number 0))
(lambda ()
(set! current-number (+ current-number 1))
current-number)))
(define number-generator (make-counter))
Each call to number-generator, will display an increasing number...
A better example is:
(let loop ((x i))
(display x)
(loop (1+ x)))
#(1 2 3)
#(1 2 3)
A list is built up of cons:
(cons 1 (cons 2 (cons 3 (cons 4 '()))))
(1 2 3 4)
(list 1 2 3 4 5 6 7 8)
(1 2 3 4 5 6 7 8)
This is in improper list
(cons 1 (cons 2 (cons 3 4)))
(1 2 3 . 4)
(cons 1 2)
(1 . 2)
A function ending in "?" returns a boolean value. A function ending in "!" is a function or a macro with side effects. (if TEST THEN ELSE)
(if (= 5 5) #t #f)
#t
The coolest if I've seen.
((if #f + *) 3 4)
(cond ...)
Each clause looks like ( ...)
(cond
((< 4 1) #f)
((= 6 7) #f)
(else #t))
#t
Clauses can also be written as (test => )
(cond
((< 4 1) => #f)
((= 6 7) => #f)
(else #t))
"An error occurred."
(case ...)
Each clause looks like: (( ...) ...)
The last clause can look like (else )
(case (* 2 3)
((2 3 5 7) 'prime)
((1 4 6 8) 'composite)
(else 'whoKnows))
composite
Sequentially evaluate all the expressions left to right, and return the last result. (begin ...) Suppose I have a function that has 10 optional arguments. It would be silly to force the user of the function remember each argument. Instead the person can use keywords. ie:
These two function calls are the same:
(make-window #:width 800 #:height 100 #:color green #:font Arial)
(make-window #:height 100 #:width 800 #:font Arial #:color green)
info:guile#POSIX create a local environment with local variables or definitions
(let ((x 5))
(define (someFunc y) (+ 5 y))
(someFunc x))
10
This is how promises are made... (delay ) returns a promise, which can be called by (force) to evaluate
,optimize (+ 2 (+ 3 2 ) 1)
You should see the resulting code become 8. This means that the guile optimizer would simple turn =(+ 2 (+ 3 2) 1) into 8, when it compiles the program. This is one example of how guile makes code run faster.
~,x functionName~ will show you the bytecode of your code. http://ds26gte.github.io/tyscheme/index.html http://www.schemers.org/ https://mitpress.mit.edu/sicp/sicp.html
Some of your guile scripts may accept arguments. Guile has a command that helps you parse those arguments. To use this facility, include this near the top of your file.
(use-modules ice-9 getopt-long)
How to design programs http://www.htdp.org/2003-09-26/Book/curriculum-Z-H-1.html#node_toc_start
The Scheme Programming Language http://www.scheme.com/tspl3/
Structure and Interpretation of Computer Programs https://mitpress.mit.edu/sicp/full-text/book/book.html
(use-modules (srfi srfi-19))
(display (date->string (current-date)
"~H:~S"))
(newline)
Maybe I should implement more srfi modules for guile.
(getcwd)
"An error occurred."
(chdir)
(use-modules (web uri))
(uri->string (build-uri 'https #:host "www.gnu.org")) Guile comes with a web client! This is like a headless firefox. It's actually like curl!
So here's an example:
(http-get (string->uri "http://localhost/html/oops.html"))
"An error occurred."
This does a get request on that uri! How cool is that! I can use guile to do GET, PUT, POST, etc.
The way the Web works, is my web server gets a web request. Then my web server sends a web response. So my handler needs to build web responses, via build-response. https://savannah.gnu.org/forum/forum.php?forum_id=8705
Modern operating systems cannot guarantee that GETs and POSTs to localhost, come from localhost. AKA if you are running a server on localhost, you have to assume that anyone on the internet can run queries against it. Use named pipes or unix sockets to ensure only local execution only. https://libfive.com/studio/ https://dthompson.us/projects/chickadee.html
:Answer:
(define* (silly #:extra)
(when extra
#t)
#f)
:END:
(define* (cool #:key more)
(when more
#t
#f))
(display (cool #:more #t))
:answer: #f :END:
:answer:
(define* (awesome #:key (more 5))
more)
(display (awesome))
(display (awesome #:more 3))
53
:END: :answer:
(let loop ((i 1))
(when (< i 11)
(display i)
(display " ")
(loop (+ i 1))))
(display "\n")
:END:
(+ 1 #| 1 |# 2)
:answer: 3
guile apparently supports a nested comment! Weird right?
#| is the beginning on the commend and #| is the end.
(+ 1 #| 1 |# 2)
#:RESULTS 3 :END:
:answer: The access? (path how) procedure.
(access? "~/Downloads/autotools.pdf" 'R_OK)
(access? "~/Downloads/autotools.pdf" 'W_OK)
;; or
(access? "~/Downloads/autotools.pdf" (logior 'R_OK 'W_OK))
;; the other ones are X_OK (execute) and F_OK (file exists).
:END:
:answer:
(use-modules (ice-9 textual-ports))
(let ((port (open-output-file "/tmp/file.txt")))
(put-string port "Hello World!\n")
(force-output port))
#
cat /tmp/file.txt
Hello World!
:END:
:answer: let* bindings are performed sequentially. So one variable can be defined in terms of the previous ones
(let* ((a 2) (b (+ a 1)) (c (+ a b)))
;;code here
)
letrec will let you define a variable with a lambda
(letrec ((a (lambda () (+ 5 7))))
;; code
)
letrec* will let you define a variable with a lambda and it defines all of the variables sequentially.
(letrec* ((a (lambda ()
(+ 5 3)))
(b (lambda ()
(+ 8 a))))
;; code here
)
:END:
:answer:
(use-module (ice-9 readline))
:END: :answer: (use-module (ice-9 match)) :END:
:answer: #(1 2 3 4) :END:
:ANSWER: An alist is an association list. It is a list of key and value pairs.
Alist = '( (car . cdr) (key . value) ...) :END:
:ANSWER: acons
(set! task-list (acons 3 "pay gas bill"))
The problem with acons is that it will let you have multiple key -> value pairs, where key are not guaranteed to be unique.
If you want unique keys, then one should use assq-set!, assv-set!, and assoc-set! :END:
:answer: A continuation is the code that is run after a given function or expression is returned. :END:
(define (silly)
(bar)
(+ 5 2)
(- 4 1))
what is the continuation after (bar) is run?
:answer: (+ 5 2) (- 4 1) :END:
:answer: Latent typing means that there is no way to determine that a variable in scheme will ALWAYS be of a certain type.
It's type may change during execution. :END: https://stackoverflow.com/questions/46656074/how-to-read-post-data-in-the-guile-web-server
https://git.sr.ht/~amz3/guile-gotofish/tree/master/web/decode.scm
https://git.sr.ht/~amz3/guile-gotofish/tree
This is the guy who made the above code: amirouche@hyper.dev
it is currently licensed under the GPL, but guile is LGPL...