This is just a little note for myself and anyone else who might have used the feature expressions and found them not working when within a module. You need to define any features at the top level.
This means that to use feature expressions in a module you must do something like this:
(require (lib "feature-expressions.ss"))
(add-feature ':testing)
(module mymod mzscheme
#+:testing (display "This is a test")
)
Hope the holidays found you happy and the new year finds you inspired to try something new.
XNA Game Express Studio is out! I really like the idea behind this product. The ability to write games for either Windows and the Xbox 360 is very appealing. I’m just that kind of person. I bought an HP48 because it could do graphs and I could write software for it. I bought a PS2 because I could get PS2 Linux. This is certainly one more reason to get a 360, besides Assassin’s Creed.
I can’t say I really have a plan for it. I just like tinkering.
There are some things to not like about it for sure. For one, and this is unsubstantiated, but I believe it only allows you to write C#, not C++ or other .NET languages even. Still, C# is a decent language, if not my favorite.
So I’ve taken a small break from Lisp to play around with Scheme. I was intrigued by Bill Clementson’s claim that the best open source Lisp was PLT Scheme.
To just test things out, I played around with the FFI that I was using for porting Omega. It’s nice and clean and worked, at least on Windows. I did notice though that Scheme lacks feature expressions, or conditional compilation for Lisp. A few hours later scanning the docs, and PLT Scheme now supports them, thanks to its integrated reader macro support.
Here is the entire implementation:
(module feature-expressions mzscheme
(provide *features* enable-conditional-compile add-feature remove-feature)
;; Provides raise-read-error and raise-read-eof-error
(require (lib "readerr.ss" "syntax")
(prefix ^ (lib "1.ss" "srfi")))
; this is the list of features that the feature expressions check against
; when compiling
(define *features* '(plt scheme))
(define add-feature
(lambda (feature)
(unless (member feature *features*)
(set! *features* (cons feature *features*)))))
(define remove-feature
(lambda (feature)
(^remove! (lambda (f) (eq? f feature)) *features*)))
(define eval-feature-expression
(lambda (fexp)
(letrec ((in-feature
(lambda (feature)
;(display feature)
;(newline)
(cond
((and (symbol? feature) (eq? feature 'and))
'and)
((and (symbol? feature) (eq? feature 'or))
'or)
; if it's a pair or list, then evaluate that sub expression
((pair? feature)
(map in-feature feature))
((symbol? feature)
(if (member feature *features*) #t #f))
; #f evaluates to #f of course
((eq? feature #f)
#f)
; any object that isn't a symbol will evaluate to #t
(else
#t)))))
(if (pair? fexp)
(eval (map in-feature fexp))
(in-feature fexp)))))
(define enable-conditional-compile
(lambda ()
(let ((cond-dispatch
(case-lambda
((ch port)
(let ((fexp (read port))) ; (read/recursive port #f (current-readtable)))
(cond ((eq? ch #\+)
(unless (eval-feature-expression fexp)
(begin (read port) (void))))
((eq? ch #\-)
(when (eval-feature-expression fexp)
(begin (read port) (void))))
(else
(error 'feature-expressions "something bad happened. Unknown char ~v" ch)))))
((ch port src line col pos)
(let ((fexp (read port))) ; (read/recursive port #f (current-readtable)))
(cond ((eq? ch #\+)
(unless (eval-feature-expression fexp)
(begin (read port) (void))))
((eq? ch #\-)
(when (eval-feature-expression fexp)
(begin (read port) (void))))
(else
(error 'feature-expressions "something bad happened. Unknown char ~v" ch))))))))
(current-readtable
(make-readtable (current-readtable)
#\+ 'dispatch-macro cond-dispatch
#\- 'dispatch-macro cond-dispatch))
(current-readtable))))
; set the feature expressions in the current readtable
(current-readtable (enable-conditional-compile))
)
I thought it was pretty straightforward. I really like case-lambda. Add support for constants and types in addition to parameters and you’d almost have Haskell like pattern invocations. Hmm….