Haskell: A Pretty Nice Language

May 19, 2009 at 4:43 pm | In Uncategorized | 2 Comments

I was going through one of those “every language sucks” periods a few days back, so I decided to do something productive and learn me a Haskell. So far, I’m liking it: the pure functional style isn’t as hard as I expected, monads are okay after a bit (though I’m still a little suspicious of them), the strict typing isn’t too much of a burden, the polymorphic types are bliss to use, and the pattern matching is simply wonderful.  It also comes with an extensive set of libraries and a central repository, which is nice to find in a non-mainstream language. Overall, I think Haskell is a good language to know.

Super-Makefile has levelled up! SuperMakefile became BashBuild!

May 8, 2009 at 11:55 pm | In coding | Leave a Comment

I had just about reached the limits of what was possible with just a makefile, but I still felt like adding more. So I rewrote the thing today as a shell script. Now, you simply call it as ‘./configure’, and it generates the Makefile for you. The script is still configured in much the same manner as the old Makefile, except now you don’t have to specify a compiler.

More importantly, the rewrite has allowed a whole bunch of new tricks, including:

  • Command-line specification of the install prefix
  • Now the commands are familiar to anyone who has ever done a “./configure && make && sudo make install” before
  • Out of source builds are now implemented
  • Autodetection of the C compiler

And most importantly:

  • Plenty of room to grow

Unfortunately, the code took a major step backwards in attractiveness. Over the next few days I may tinker around with it in an attempt to make it not look quite so bad, and possibly move more logic out into the configure script.

Other major news of the day: I finally dumped bzr for git, just so I could use GitHub. The new project is named BashBuild.

Revenge of the Super-Makefile

May 5, 2009 at 8:35 pm | In coding | Leave a Comment
Tags: , ,

So today I found some more things that the old Makefile was lacking. An “install” target, a “.PHONY” target to prevent breakage down the line, and the ability to recursively build subprojects. A few hours later, I have this:

PROJECT=foo
VERSION=0.0.1
SOURCES=bar.c baz.c
SUBPROJECTS=xyzzy fnord
LIBRARY=-lm
INCPATHS=xyzzy fnord
LIBPATHS=fnord
PREFIX=/usr/local
LDFLAGS=
CFLAGS=-c -Wall -g
CC=gcc

# ------------ MAGIC BEGINS HERE -------------

# We want subprojects to use these variables
export CC
export PREFIX

# Automatic generation of some important lists
OBJECTS=$(SOURCES:.c=.o)
INCFLAGS=$(foreach TMP,$(INCPATHS),-I$(TMP))
LIBFLAGS=$(foreach TMP,$(LIBPATHS),-L$(TMP))

# Set up the output file names for the different output types
ifeq "$(LIBRARY)" "shared"
    BINARY=lib$(PROJECT).so
else ifeq "$(LIBRARY)" "static"
    BINARY=lib$(PROJECT).a
else
    BINARY=$(PROJECT)
endif

all: $(SOURCES) $(SUBPROJECTS) $(BINARY)

$(BINARY): $(OBJECTS)
ifdef SOURCES
    # Assemble the object files into the right type of binary
    ifeq "$(LIBRARY)" "static"
        ar rcs $(BINARY) $(OBJECTS)
    else ifeq "$(LIBRARY)" "shared"
        $(CC) -shared $(LIBFLAGS) $(OBJECTS) $(LDFLAGS) -o $@
    else
        $(CC) $(LIBFLAGS) $(OBJECTS) $(LDFLAGS) -o $@
    endif
endif

$(SUBPROJECTS):
        make -e -C $@

.c.o:
        $(CC) $(INCFLAGS) $(CFLAGS) -fPIC $< -o $@ 

install:
        @ for i in $(SUBPROJECTS); do make -e -C $${i} install; done
ifdef SOURCES
    ifeq "$(LIBRARY)" "static"
        install $(BINARY) $(PREFIX)/lib
    else ifeq "$(LIBRARY)" "shared"
        install $(BINARY) $(PREFIX)/lib
    else
        install $(BINARY) $(PREFIX)/bin
    endif
endif

distclean:
        rm -f $(BINARY) $(OBJECTS)
        @ for i in $(SUBPROJECTS); do make -C $${i} distclean; done

clean:
        rm -f $(OBJECTS)
        @ for i in $(SUBPROJECTS); do make -C $${i} clean; done

.PHONY: all clean distclean install $(SUBPROJECTS)

It’s longer, but not by too much, and now I can safely say it has everything I have ever needed in a fancy build system. It would be nice if I could get pretty colourized output, but this Makefile reliably builds, cleans, and installs the projects I have tested it on.

The Super-Makefile

May 4, 2009 at 8:36 pm | In coding | Leave a Comment
Tags: , ,

After toying with build systems off and on for months, I concluded today that make is about as advanced as I ever need to get for my projects. In the past, I recall using this gem of a Makefile.  But my needs in a build process have grown a little. First of all, I now prefer C to C++, so that had to be changed. Then I had to go about adding static and shared library abilities to it. Then I added “clean” and “distclean” build targets, and include and library search paths got introduced somewhere along the way.

After good half hour of modification, I had the following Makefile, posted here mainly so I can find it easily from any computer. By modifying the first six variables defined in the Makefile, it can be adapted to almost any C project of reasonable complexity. It has no support for cross-platform library identification, out-of-source builds, or debug and release build toggles. But on the other hand, I can never get those things to work right any way.

Toggling between static library, shared library, and executable build modes is performed by setting the LIBRARY variable to “static”, “shared”, or anything that isn’t those two values.

PROJECT=foo
SOURCES=bar.c baz.c
LIBRARY=nope
INCPATHS=../some_other_project/
LIBPATHS=../yet_another_project/
LDFLAGS=-ldosomething
CFLAGS=-c -Wall
CC=gcc

# ------------ MAGIC BEGINS HERE -------------

# Automatic generation of some important lists
OBJECTS=$(SOURCES:.c=.o)
INCFLAGS=$(foreach TMP,$(INCPATHS),-I$(TMP))
LIBFLAGS=$(foreach TMP,$(LIBPATHS),-L$(TMP))

# Set up the output file names for the different output types
ifeq "$(LIBRARY)" "shared"
    BINARY=lib$(PROJECT).so
    LDFLAGS += -shared
else ifeq "$(LIBRARY)" "static"
    BINARY=lib$(PROJECT).a
else
    BINARY=$(PROJECT)
endif

all: $(SOURCES) $(BINARY)

$(BINARY): $(OBJECTS)
    # Link the object files, or archive into a static library
    ifeq "$(LIBRARY)" "static"
        ar rcs $(BINARY) $(OBJECTS)
    else
        $(CC) $(LIBFLAGS) $(OBJECTS) $(LDFLAGS) -o $@
    endif

.c.o:
        $(CC) $(INCFLAGS) $(CFLAGS) -fPIC $< -o $@

distclean: clean
        rm -f $(BINARY)

clean:
        rm -f $(OBJECTS)

Fixing Broken Macros with Eval and Quasiquote

March 21, 2009 at 8:20 pm | In coding, lisp, scheme, tutorial | 2 Comments
Tags: , ,

Recently, I found myself needing to deal with a “convenience” macro, which quoted several of its arguments for me before passing them along to the real function.  Unfortunately, only the macro was exported from the library, and I was unable to access the base function.

(define-syntax convenient-function
  (syntax-rules ()
    ((_ arg1 arg2) (much-harder-function 'arg1 'arg2))))

How useful.  To save me a handful of quotes, I lose the ability to programmatically generate my arguments.

As I was loath to reimplement the entire library just to regain that ability, I looked for another solution.  Thankfully, I found one.

(define (much-harder-function arg1 arg2)
  (eval `(convenient-function ,arg1 ,arg2)
        (environment '(convenient-lib))))

As far as I can tell, this circumvents the macro’s quoting features entirely to allow me to pass in a dynamically generated symbol.  While it won’t work with functions which modify the environment, it worked well in my case, and allowed me to move on to more interesting code.

SRFI-0 for Detecting Scheme Implementation

March 14, 2009 at 6:44 pm | In scheme | 1 Comment
Tags: ,

I found out earlier today that SRFI-0 can be used to determine the host Scheme in some cases.  Here is the result of my testing, in case someone finds it useful:

No SRFI-0 by default:

  • mzscheme
  • ikarus
  • scheme48

Name exported for cond-expand:

Scheme Name     SRFI-0 Feature Name
CHICKEN chicken
Guile guile
Bigloo bigloo
Gambit gambit
MIT Scheme mit
Gauche gauche

Runtime Scheme Detection

March 14, 2009 at 4:33 pm | In coding, scheme | 1 Comment
Tags: ,

I really want my code to be “write once, run anywhere”, at least as far as Schemes go.  R6RS library features make strides toward that goal.  Only, there’s not many R6RS Schemes.  Since there are a whole lot of R5RS ones, I’d like to include R5RS in the portability fun.

In many cases, enough functionality appears in all major implementations to make some major steps toward portability.  So a while back, I decided to get a few things out of the way (you know, processes, FFI, things like that).

To make simple, portable libraries, we need to find out some details about the Scheme implementation the code is running under.  Unfortunately, there is no standard way to do this.  We could just call a function and see if it worked, but then we throw an error, and there’s no standard way to trap those in R5RS.  And even if a function of the given name existed, we still don’t know what arguments it takes, because that differs too.

So we’re left with some sort of indirect detection method,  guessing the implementation based on a bunch of unrelated tests.

So I gathered a list of as many nonstandardized/undefined behaviours as possible (mainly from this table, and grepping the R5RS spec for the word “undefined”).  Then I filtered those differences down to a bunch of tests that won’t error out.  Then I took the tests that gave meaningful results, and because I had enough of those to be picky, I took only tests which fit on a single line.

The resulting set of 20 tests generates a sort of “signature” — a list of twenty boolean values that identifies the host Scheme.

Currently the code works on:

  • MzScheme
  • CHICKEN
  • Guile
  • Bigloo
  • Gambit
  • Ikarus
  • Scheme48
  • MIT Scheme
  • Gauche

This is actually a list of all the implementations I have installed right now, and other implementations can be supported just by adding another line to the signatures list.

On Scheme implementations which provide a compiled and an interpreted mode, only interpreted has been tested (I don’t really know how to use a compiled Scheme, so I didn’t).  Some Schemes have different behaviour interpreted and compiled, so caution should be used there.

Enough talk, here’s the code:

;;;
;;; DETECT
;;;   A set of functions to allow an interpreted Scheme
;;;    program to determine the implementation it is
;;;    running under.
;;;

;;
;; DETECT:SIGNATURE
;;   Assemble a signature for the current
;;   Scheme implementation.
;;
(define (detect:signature)
  (list
    ;; AXCH: exact-sqrt
    (exact? (sqrt 4))
    ;; AXCH: exact-times-zero
    (exact? (* 0 3.1))
    ;; AXCH: exact-div-zero
    (exact? (/ 0 4.7))
    ;; AXCH: exact-rationals
    (exact? (/ 1 3))
    ;; AXCH: case-sensitive
    (eq? 'a 'A)
    ;; AXCH: promises-are-thunks
    (procedure? (delay 3))
    ;; Do strings made from numbers less than 1 omit the 0?
    (string=? ".5" (number->string 0.5))
    ;; AXCH: literal-rationals
    (number? (string->number "1/2"))
    ;; AXCH: literal-complexes
    (number? (string->number "1+i"))
    ;; Is the empty string eqv to itself?
    (eqv? "" "")
    ;; How about the empty vector?
    (eqv? '#() '#())
    ;; A non-empty string?
    (eqv? "a" "a")
    ;; Does SET! have a constant return value?
    (let ((x 0)) (eqv? (set! x 1) (set! x 'asd)))
    ;; Is it equal to other undefined things?
    (eqv? (for-each (lambda (x) #t) '(0 1 2)) (let ((x 123)) (set! x 321)))
    ;; Are negative and positive inexact zero the same?
    (eq? +0.0 -0.0)
    (eqv? +0.0 -0.0)
    (equal? +0.0 -0.0)
    ;; Is the default vector filled with zeroes?
    (equal? (make-vector 5) '#(0 0 0 0 0))
    ;; Is the default vector filled with falses?
    (equal? (make-vector 5) '#(#f #f #f #f #f))
    ;; Vector-fill returns a vector?
    (vector? (vector-fill! (make-vector 1) 0))
    ))

;;
;; DETECT:KNOWN-SIGNATURES
;;   A precalculated list of signatures for all supported
;;    Scheme implementations.
;;
(define detect:known-signatures
'((mzscheme   (#t #t #t #t #f #f #f #t #t #f #f #f #t #t #f #f #f #t #f #t))
  (chicken    (#f #f #f #f #f #f #f #t #f #f #f #f #t #t #f #t #t #f #f #f))
  (guile      (#f #t #f #t #f #f #f #t #t #t #f #f #t #t #f #f #t #f #f #f))
  (bigloo     (#f #f #f #f #f #t #f #f #f #f #f #f #t #t #f #t #t #f #f #f))
  (gambit     (#t #t #t #t #f #f #t #t #t #f #f #f #t #t #f #f #f #t #f #f))
  (ikarus     (#f #f #f #t #f #t #f #t #f #f #f #f #t #f #f #t #t #t #f #f))
  (scheme48   (#f #f #f #t #t #t #f #t #t #t #t #t #t #t #t #t #t #f #f #f))
  (mit-scheme (#t #t #t #t #t #f #t #t #t #f #t #f #f #f #f #t #t #f #t #f))
  (gauche     (#f #f #f #t #f #f #f #t #t #f #f #f #f #f #f #t #t #f #f #f))))

;; DETECT:MATCH-SIGNATURE
;;   Determine the name of the current Scheme implementation
;;    by checking the signature returned by DETECT:SIGNATURE
;;    against a table of known signatures.
(define (detect:match-signature)
  (let ((signature (detect:signature)))
    ; Loop over the DETECT:KNOWN-SIGNATURES list
    (let test ((siglist detect:known-signatures))
      (if (equal? '() siglist)
        ; Return 'UNKNOWN if we're stumped
        'unknown
        (let ((testsig (car siglist)))
          (if (equal? (cadr testsig) signature)
            (car testsig)
            (test (cdr siglist))))))))

;;
;; DETECT:NAME
;; Memoized form of DETECT:MATCH-SIGNATURE
;;
(define detect:name
  (let ((memo #f))
    (lambda ()
      (and (not memo)
           (set! memo (detect:match-signature)))
      memo)))

Obviously, only the memoized DETECT:NAME is meant for general use, since a program generally won’t the see the host changing as it runs, and repeatedly calculating the name would be inefficient.  I don’t actually have much experience with Scheme, so the DETECT:MATCH-SIGNATURE function could probably be written more efficiently, but it works.

Anyway, I hope that someone finds this to be useful.  I have used it to write the beginnings of a portable process library.  More on that after I get around to polishing it up a bit more.

Retraction

January 15, 2009 at 11:45 pm | In coding, lisp, scheme | 1 Comment
Tags: , ,

It would appear that point #4 of my earlier proposal is entirely unnecessary.   A modifiable load function, like the one found in CHICKEN Scheme, can be implemented as follows:

(define (load path . evalproc)
 (let ((eval (lambda (expr) (eval expr (interaction-environment)))))
   (if (and evalproc              ;; Do some checks on the procedure
            (list? evalproc)
            (> (length evalproc) 0)
            (procedure? (car evalproc)))
        (set! eval (car evalproc)) ;; True
        #f)                        ;; False
   (letrec ((eval-datum (lambda ()
                          (let ((datum (read)))
                            (if (eof-object? datum)
                                path
                                (begin
                                  (eval datum)
                                  (eval-datum)))))))
     (with-input-from-file path eval-datum))))

Some of this code is probably unnecessary, but I felt it better to err on the side of checking too much before using the optional evaluation procedure.  I could also trivially rewrite it to use the more clear DO form, rather than a tail-recursive lambda.  Also, it might be more adviseable to use the standard LOAD function if no special evaluation procedure is given.  I’m torn on that last one.  Whatever.

But anyway, I see now that I really should have given the matter some deeper thought before immediately writing a lengthy proposal to change fundamental language features.  Over the next few days, I intend to work on a Scheme implementation detection library.  If I am successful, the two most important points of my earlier proposal will have been fulfilled, and I will be content.

It’s been a learning experience.

Scheme Load Return Values

January 15, 2009 at 10:21 pm | In coding, scheme | 3 Comments
Tags: , , , , , , ,

Shortly after finishing my previous post, I began to wonder if maybe some of the features I had requested were available already.  I was pleasantly surprised.

Implementations tested were:

Bad news first.  In my hour or so of testing, I was unable to find any way to directly return values from a loaded file in Guile, Gambit, and STklos.

On the other hand, that means that four of the seven implementations that I tested could return values.

MzScheme and MIT Scheme both return the last form, whatever it was.  If the last form was a DEFINE statement, MzScheme returns nothing, and MIT Scheme returns the identifier that was defined.

Bigloo doesn’t seem to return anything usable, but it does print the results of intermediate evaluations, and claims to return the result of the last evaluation.  This may indeed be true, but in my testing I was unable to get it to return anything other than the path of the just-loaded file.

Chicken, however, was an unqualified success.  Although it is true that at first it returns nothing from its LOAD function, it provides a brilliant little mechanism to fix that.  The LOAD function, in addition to taking a filename, will also take an optional argument called EVALPROC, which is called repeatedly with each form from the loaded file.  This fact, combined with a little closure magic, ends us up with this:

(define (load-return file)
  (let ((return '()))
    (load file
	  (lambda (exp)
	    (if (and (list? exp) (eqv? (list-ref exp 0) 'define))
	        (begin
		  (eval exp)
		  (set! return (cons (list-ref exp 1) return)))
                (set! return (cons (eval exp) return)))))
    (reverse return)))

This function calls the LOAD function, but passes it its own evaluation procedure, which will assemble a list of values when called, as well as evaluating each expression.

After seeing the beautiful and elegant way in which Chicken Scheme allows the user to dynamically alter the behaviour of the LOAD function at runtime, I feel like I should alter my recommendation for modifying that behaviour.  Chicken has, I believe, found the best possible way to implement such functionality: have a reasonable default, but allow people to override it if they wish.  Simple, elegant, and powerful: exactly like the language itself.  Bravo, Chicken.

Bravo.

We Need An R5.1RS

January 15, 2009 at 8:49 pm | In idiocy, retracted | 11 Comments
Tags:

Even Newer Edit: R6RS is decent, it’s not worth the effort to reimplement the work they’ve done.

Edit: I have, for the most part, realized that this post was an error.  After a few more hours of thought, I have come to the conclusion that implementation detection and redefining the load function are tasks eminently better fitted to an external library than to a modification to the core language.  While I still believe that Unicode and Unix shebangs are desirable features in the core language, enough implementations support these things that I don’t really feel the need to raise a fuss about it.

« Previous PageNext Page »

Blog at WordPress.com. | Theme: Pool by Borja Fernandez.
Entries and comments feeds.