I have a hello world pdf program written.
Just run this and it will generate a PDF with a big Hello World!
This is Sid's Blog on Lisp, Scheme and everything in between.
'(:name "sid" :language "lisp")
'(:name "hello" :function (lambda () (format t "Hello World~%"))) ; Bad
`(:name "hello" :function ,(lambda () (format t "Hello World~%")))
I was doing a lot of builds at work today. While waiting for it to complete, I decided to spend some time coding in Lisp. Clozure CL host irc logs for #ccl, #scheme and #lisp on their website. I thought it would be cool idea to download the logs for a particular date by writing a CL program.
What it turned out to be was a huge waste of time. I decided to try the trivial-http library. I downloaded the tarball. Then I didn't quite know how to install it. Some amount of googling gave me links to asdf-install. I then spent the next couple hours trying to get it work. It doesn't work. Checked on #lisp, and #ccl but no responses.
In frustration, I turned on DrScheme and grokked the documentation. There is a net/url library that is shipped with PLT Scheme. Two minutes later my code looked like so
(require net/url)
(display-pure-port (get-pure-port (string->url "http://ccl.clozure.com/irc-logs/lisp/2009-12/lisp-2009.12.28.txt")))
I'm not sure if any other scheme (other than maybe chicken) would have allow me to get going so quickly. I doubt whether any further example is required for a batteries included distro of CL.
Update: Finally got something in CL - a TCP stream descriptor. So, we aren't there yet. But here is how it goes.
What we have now is just a stream. We now need to read the stream. That's for later.
(define (file-size filename)
(call-with-input-file filename (lambda (port)
(let loop ((c (read-char port))
(count 0))
(if (eof-object? c)
count
(loop (read-char port) (+ 1 count)))))))
(file-size "input.txt")
(file-size "/input.txt")
(defun square (x) (* x x))
(disassemble #'square)
Disassembly of function SQUARE 1 required argument 0 optional arguments No rest parameter No keyword parameters 4 byte-code instructions: 0 (LOAD&PUSH 1) 1 (LOAD&PUSH 2) 2 (CALLSR 2 57) ; * 5 (SKIP&RET 2) NIL
; disassembly for SQUARE ; 23B6C274: 8BD3 MOV EDX, EBX ; no-arg-parsing entry point ; 76: 8BFB MOV EDI, EBX ; 78: E8304049FE CALL #x220002AD ; GENERIC-* ; 7D: 7302 JNB L0 ; 7F: 8BE3 MOV ESP, EBX ; 81: L0: 8B5DFC MOV EBX, [EBP-4] ; 84: 8BE5 MOV ESP, EBP ; 86: F8 CLC ; 87: 5D POP EBP ; 88: C3 RET ; 89: CC0A BREAK 10 ; error trap ; 8B: 02 BYTE #X02 ; 8C: 18 BYTE #X18 ; INVALID-ARG-COUNT-ERROR ; 8D: 4D BYTE #X4D ; ECX NIL
Here's the simplest way to deliver an Hello World program on Windows. I'm going to use clisp for this, which does not compile to native code, but only bytecode.
The program that prints hello world is simple -
(defun hello-world ()
(format t "Hello, World~%"))
(progn
(hello-world)
(format t "Enter any key to exit...")
(read)
(exit))
[1]> (compile-file "hw.lisp")
This will now generate a bytecompiled file - hw.fas.
Now, save an image of the clisp
[2]> (saveinitmem "hello.exe" :executable t :quiet t
:init-function #'(lambda () (load "hw.fas")))
Now, this will generate an executable - hello.exe.
Copy hello.exe, hw.fas into a new directory that you want to use as the installation target directory. Copy readline5.dll, libintl-8.dll and libiconv-2.dll from
Now you can zip this directory or create an installer using InstallJammer or NSIS.
That's it!
One caveat though. You may need to ship readline as well. That's available in
; GAMBIT
; (run-program
; (lambda (program)
; (let ((port
; (open-process
; (list path: "/bin/sh"
; arguments: (list "-c" (string-append "exec " program))
; stderr-redirection: #t))))
; (list port port))))
;
; (flush-output-port force-output)
; GAMBIT / Windows
(run-program
(lambda (program)
(let ((port
(open-process
(list path: "c:/tcl/bin/tclsh85.exe"
stderr-redirection: #t))))
(list port port))))
(flush-output-port force-output)
(define f (tk 'create-widget 'frame))
(define b (f 'create-widget 'button))
(b 'configure 'text: "Hello World")
(tk/pack b)
(tk/pack f)
We know that gambit-c allows you to compile scheme code into native executables by generating C files and then running them through a C compiler such as gcc. There are real advantages of doing so. You can even compile scheme to run an app on the iPhone.
On Windows, follow these steps to write your first hello world program that gambit then compiles to an executable.
You now have an exe that prints hello world.
Here's a small scheme example that prints hello world.
(define (hw)
(begin
(display "Hello World")
(newline)))
(hw)
Have spent lots of time trying to understand syntax-case, yet there are no simple examples. At least until I came across this post.
Small change for Iron Scheme -
(define-syntax is-nil?
(lambda (stx)
(syntax-case stx ()
((_ ()) #t)
((_ stx) #f))))
If you were like me and skipped through most of the chapter on quote, quasiquote and splicedquote, then you made a bad mistake. This part is particularily important as the whole macro business is dependent on this. So here's a refresher.
Very simply put quote just quotes its arguments. So, when we execute the following, we get the output as test.
(import (rnrs))
(define foo 'test)
(display foo)
Quasiquote allows us to do more. It allows us have a template which we can fill in with values. Consider the following.
(import (rnrs))
(define x 10)
(display `(list x ,x))
The output will be (list x 10). However, the advantage of quasiquote goes much beyond just templates. We can use it to debug our code better.
Now, we want to understand how fact works. So, let us re-write fact not to compute the value but to just print out the expanded s-expressions.
(import (rnrs))
(define (fact n)
(cond
((or (= n 0) (= n 1)) n)
(else (* n (fact (- n 1))))))
(display (fact 5))
(import (rnrs))
(define (fact n)
(cond
((or (= n 0) (= n 1)) n)
(else `(* ,n ,(fact (- n 1))))))
(display (fact 5))
Now the output is more interesting - (* 5 (* 4 (* 3 (* 2 1)))). What quasiquote and unquote ended up showing us is how the expression is calculated. Now, the fact example is trivial but it does give us an insight into the computation involved.
Related to quote is spliced-quote. If we use spliced-quote then the output of a list is expanded. So,
(import (rnrs))
(define foo `(1 ,@(list 2 3)))
(define bar `(1 (list 2 3)))
(display foo)
(newline)
(display bar)
(newline)
will give us the output as (1 2 3) and (1 (list 2 3)).
What does that mean? It means you create a macro that is lexically
bound. That means, let-syntax acts just like let, but it works on
syntax rather than variables. This means we can use let-syntax to
create localized macros. Consider this example..
(import (rnrs))
(define (hw n)
(display n)
(newline))
(let-syntax ((hw
(syntax-rules ()
((_ 0) (begin
(display "Hello World")
(newline)))
((_ n) (begin
(display "Goodbye World")
(newline))))))
(begin
(hw 0)
(hw 1)))
(hw 0)
(hw 1)
The (hw 0) and (hw 1) inside let-syntax end up printing "Hello World"
and "Goodbye World", whereas the (hw 0) and (hw 1) outside the scope,
print 0 and 1.
(import
(rnrs)
(ironscheme clr)
(ironscheme clr shorthand))
(clr-reference System.Windows.Forms)
(clr-reference System.Drawing)
(clr-using System.Windows.Forms)
(clr-using System.Drawing)
;; Macros
;; Macro to set a property
(define-syntax set-property!
(syntax-rules (:button :form)
((set-property! :button button text x y)
(let ((b button))
(with-clr-type ((b Button))
(b : Text = text)
(b : Location = (clr-new Point x y)))))
((set-property! :form form text)
(let ((f form))
(with-clr-type ((f Form))
(f : Text = text))))))
;; Main Function that runs the form
(define (run form controls b1 b2)
(let ((mc controls))
(begin
(with-clr-type ((mc Form+ControlCollection))
(mc : Add (b1))
(mc : Add (b2))))
;; SHOW FORM AND RUN PUMP
(clr-static-call System.Console WriteLine "Start")
(clr-static-call Application (Run Form) form)
(clr-static-call System.Console WriteLine "Stop")
;; REMOVE CONTROLS
(with-clr-type ((mc Form+ControlCollection))
(mc : Remove (b1))
(mc : Remove (b2)))))
;; SETUP EVENTS
(define (make-event-handler text)
(lambda (s e)
(display text)
(newline)))
(define mainForm_MouseEnter (make-event-handler "Enter"))
(define mainForm_MouseLeave (make-event-handler "Leave"))
(define btnGo_Click (make-event-handler "Go"))
(define btnStop_Click (make-event-handler "Stop"))
(begin
;; INITIALIZE
(define mainForm (clr-new Form))
(define btnGo (clr-new Button))
(define btnStop (clr-new Button))
(define mainControls (clr-prop-get Form Controls mainForm))
;; APPLY EVENTS
(clr-event-add! Form MouseEnter mainForm mainForm_MouseEnter)
(clr-event-add! Form MouseLeave mainForm mainForm_MouseLeave)
(clr-event-add! Button Click btnGo btnGo_Click)
(clr-event-add! Button Click btnStop btnStop_Click)
(set-property! :form mainForm "Hello World")
(set-property! :button btnGo "GO" 10 20)
(set-property! :button btnStop "STOP" 100 20)
(run mainForm mainControls btnGo btnStop)
;; REMOVE EVENTS
(clr-event-remove! Form MouseEnter mainForm mainForm_MouseEnter)
(clr-event-remove! Form MouseLeave mainForm mainForm_MouseLeave)
(clr-event-remove! Button Click btnGo btnGo_Click)
(clr-event-remove! Button Click btnStop btnStop_Click))
# Generate a nice changelog from git
PREV=
for I in `git tag`; do
echo " ";
git log --pretty=format:" %s" $PREV..$I;
echo " ";
echo $I;
PREV=$I;
done | tac > CHANGELOG