;;
;; Definition and code generators for a simple applicative language for numerical simulation.
;;
;; Copyright 2010-2011 Ivan Raikov and the Okinawa Institute of
;; Science and Technology.
;;
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; A full copy of the GPL license can be found at
;; .
;;
(module flsim
(
V:C V:Var V:Rec V:Sel V:Vec V:Sub V:Ldv V:Stv V:Fn V:Prim V:Ifv
E:Val E:Ife E:Let E:Set E:Ret E:Seq E:Noop
name/scheme prelude/scheme expr->scheme value->scheme
name/ML prelude/ML expr->ML value->ML
name/Octave prelude/Octave expr->Octave value->Octave
)
(import scheme chicken)
(require-extension extras data-structures srfi-1 datatype)
(define nl "\n")
(define-datatype value value?
(V:C (v (lambda (x) (or (symbol? x) (number? x) ))))
(V:Var (name symbol?))
(V:Rec (flds (lambda (x) (and (pair? x) (every (lambda (x) (and (symbol? (car x)) (value? (cadr x)))) flds)))))
(V:Sel (field (lambda (x) (or (symbol? x) (integer? x)))) (v value?))
(V:Vec (vals (lambda (x) (every value? x))))
(V:Sub (index (lambda (x) (and (integer? x) (or (zero? x) (positive? x))))) (v value?))
(V:Ldv (v value?))
(V:Stv (v value?))
(V:Fn (args pair?) (body expr?))
(V:Prim (name symbol?) (args (lambda (x) (every value? x))))
(V:Ifv (test value?) (ift value?) (iff value?))
)
(define-record-printer (value x out)
(fprintf out "~A"
(cases value x
(V:C (v) (sprintf "V:C ~A" v))
(V:Var (n) (sprintf "V:Var ~A " n))
(V:Rec (lst) "V:Rec")
(V:Sel (f v) "V:Sel")
(V:Vec (lst) "V:Vec")
(V:Sub (i v) "V:Sub")
(V:Ldv (v) "V:Ldv")
(V:Stv (v) "V:Stv")
(V:Ifv (test tv fv) "V:Ifv ~A ~A ~A" test tv fv)
(V:Fn (args body) (sprintf "V:Fn ~A = ~A" args body))
(V:Prim (name args) (sprintf "(V:Prim ~A ~A)" name args)))))
(define-datatype expr expr?
(E:Val (name symbol?) (v value?))
(E:Ife (test value?) (ift expr?) (iff expr?))
(E:Let (bnds pair?) (body expr?))
(E:Set (loc value?) (v value?))
(E:Ret (v value?))
(E:Seq (exprs pair?))
(E:Noop)
)
(define-record-printer (expr x out)
(fprintf out "~A"
(cases expr x
(E:Val (name v) (sprintf "E:Val ~A = ~A" name v))
(E:Ife (test ift iff) (sprintf "E:Ife ~A ~A ~A" test ift iff))
(E:Let (bnds body) (sprintf "E:Let ( ~A ) ~A" bnds body))
(E:Set (loc v) (sprintf "E:Set ~A ~A" loc v))
(E:Ret (v) (sprintf "E:Ret ~A" v))
(E:Seq (lst) (sprintf "E:Seq ~A" lst))
(E:Noop () (sprintf "E:Noop"))
)))
(define (name/scheme s)
(let ((cs (string->list (->string s))))
(let loop ((lst (list)) (cs cs))
(if (null? cs) (string->symbol (list->string (reverse lst)))
(let* ((c (car cs))
(c1 (cond ((or (char-alphabetic? c) (char-numeric? c)
(char=? c #\_) (char=? c #\-)) c)
(else #\-))))
(loop (cons c1 lst) (cdr cs)))))))
(define (expr->scheme x . rest)
(let-optionals rest ((bnd? #t))
(cases expr x
(E:Val (name v)
(list "(" (name/scheme name) " " (value->scheme v) ")" nl))
(E:Ife (test ift iff)
(list "(cond (" (value->scheme test) " " nl
" " (expr->scheme ift ) ")" nl
"(else " (expr->scheme iff) "))" nl))
(E:Let (bnds body)
(list "(let* (" nl
(map (lambda (x) (expr->scheme x #t)) bnds) nl
") " nl
(expr->scheme body #f) nl
")" nl))
(E:Set (loc v)
(if (not bnd?)
(list "(" (value->scheme loc) " " (value->scheme v) ")")
(list "(_ (" (value->scheme loc) " " (value->scheme v) "))" nl)))
(E:Ret (v) (value->scheme v))
(E:Seq (exprs)
(list "(begin " (intersperse (map (lambda (x) (expr->scheme x #f)) exprs) " ") ")"))
(E:Noop () (list "(void)"))
)))
(define (value->scheme v)
(let ((result
(cases value v
(V:C (v) v)
(V:Var (name) (name/scheme name))
(V:Rec (lst)
(list "`(" (intersperse (map (lambda (nv) (list "(" (name/scheme (car nv)) " . ,"
(value->scheme (cadr nv)) ")")) lst) " ") ")"))
(V:Sel (field v)
(if (number? field)
(list "(list-ref " (value->scheme v) " " (- field 1) ")")
(list "(alist-ref '" (name/scheme field) " " (value->scheme v) ")")))
(V:Vec (lst)
(list "(list " (intersperse (map value->scheme lst) " ") ")"))
(V:Sub (index v)
(list "(list-ref " (value->scheme v) " " index ")"))
(V:Ldv (v)
(list "(" (value->scheme v) ")"))
(V:Stv (v)
(list "(make-parameter " (value->scheme v) ")" ))
(V:Fn (args body)
(list "(lambda (" (intersperse (map name/scheme args) " ") ") "
(expr->scheme body #f) ")"))
(V:Prim (name args)
(let* ((fp? (case name
((+ - * / >= > < <= neg) #t)
(else #f)))
(op (if fp? (conc "fp" name) name)))
(cond ((null? args)
(case name
((NONE) (list "#f"))
(else (list "(" name ")"))))
(fp?
(if (pair? (cdr args))
(fold-right (lambda (x ax) (list "(" op " " (value->scheme x) " " ax ")"))
(list "(" op " " (value->scheme (car args)) " " (value->scheme (cadr args)) ")")
(cddr args))
(list "(" op " " (value->scheme (car args)) ")")
))
(else
(list "(" op " " (intersperse (map value->scheme args) " ") ")")))))
(V:Ifv (test ift iff)
(list "(if " (value->scheme test) " "
(value->scheme ift) " "
(value->scheme iff) ")"))
)))
result))
(define (prelude/scheme #!key (solver 'rk4b))
`(
#<list (->string s))))
(let loop ((lst (list)) (cs cs))
(cond ((null? cs) (string->symbol (list->string (reverse lst))))
((null? (cdr cs))
(let ((c (car cs)))
(if (or (char-alphabetic? c) (char-numeric? c))
(loop (cons c lst) (cdr cs))
(loop (append (reverse (string->list (->string (gensym 't)))) lst) (cdr cs))
)))
(else
(let* ((c (car cs))
(c1 (cond ((or (char-alphabetic? c) (char-numeric? c)
(char=? c #\_) (char=? c #\#)) c)
(else #\_))))
(loop (cons c1 lst) (cdr cs))))))))
(define (expr->ML x . rest)
(let-optionals rest ((bnd? #t))
(cases expr x
(E:Val (name v)
(list "val " (name/ML name) " = " (value->ML v) nl))
(E:Ife (test ift iff)
(list "if (" (value->ML test) ") " nl
"then " (expr->ML ift ) nl
"else " (expr->ML iff) nl))
(E:Let (bnds body)
(list "let " nl
(map (lambda (x) (expr->ML x #t)) bnds) nl
"in " nl
(expr->ML body #f) nl
"end" nl))
(E:Set (loc v)
(if bnd?
(list "val _ = (" (value->ML loc) " := " (value->ML v) ")" nl)
(list (value->ML loc) " := " (value->ML v))))
(E:Ret (v) (value->ML v))
(E:Seq (exprs)
(list "(" (intersperse (map (lambda (x) (expr->ML x #f)) exprs) "; ") ")"))
(E:Noop () (list "()"))
)))
(define (value->ML v)
(cases value v
(V:C (v) (cond ((and (number? v) (negative? v))
(list "~" (abs v)))
(else v)))
(V:Var (name) (name/ML name))
(V:Rec (lst)
(list "{" (intersperse (map (lambda (nv) (list (name/ML (first nv)) " = "
(value->ML (cadr nv)))) lst) ", ") "}"))
(V:Sel (field v)
(list "(#" (name/ML field) "(" (value->ML v) "))"))
(V:Vec (lst)
(let ((n (length lst)))
(list "([" (intersperse (map (lambda (v) (value->ML v)) lst) ", ") "])")))
(V:Sub (index v)
(list "List.nth (" (value->ML v) ", " index ")"))
(V:Ldv (v)
(list "(!" (value->ML v) ")"))
(V:Stv (v)
(list "ref " (value->ML v) ))
(V:Fn (args body)
(list "(fn (" (intersperse (map name/ML args) ",") ") => "
(expr->ML body #f) ")"))
(V:Prim (name args)
(let* ((infix? (case name
((+ - * / >= > < <=) #t)
(else #f)))
(op (if infix? (list "(op " name ")") name)))
(cond ((null? args)
(case name
((NONE) (list name))
(else (list name "()"))))
((null? (cdr args))
(list "(" op " " (value->ML (car args)) ")"))
((and infix? (pair? (cddr args)))
(list "(foldr " op "(" (value->ML (V:Prim name (list (car args) (cadr args)))) ")"
"[" (intersperse (map value->ML (cddr args)) ",") "])"))
(else
(list "(" op "(" (intersperse (map value->ML args) ",") "))")))))
(V:Ifv (test ift iff)
(list "(if (" (value->ML test) ") "
"then " (value->ML ift ) " "
"else " (value->ML iff) ")"))
))
(define (prelude/ML #!key (solver 'rk4b) )
`(
#< (('b,'c) trs)) ref) *
(('a -> (('b,'c) trs)) ref) *
((('b,'c) trs) -> bool))
fun tsCase (fa,fb,x) = case x of TRSA a => (fa a) | TRSB b => (fb b)
fun trfOf x = case x of TRC (f,fk,e) => f
fun trfkOf x = case x of TRC (f,fk,e) => fk
fun treOf x = case x of TRC (f,fk,e) => e
fun trfSet (x,f') = case x of TRC (f,fk,e) => f := f'
fun trfkSet (x,fk') = case x of TRC (f,fk,e) => fk := fk'
fun putStrLn str =
(TextIO.output (TextIO.stdOut, str);
TextIO.output (TextIO.stdOut, "\n"))
fun putStr str = (TextIO.output (TextIO.stdOut, str))
fun showReal n =
let open StringCvt
in
(if n < 0.0 then "-" else "") ^ (fmt (FIX (SOME 12)) (abs n))
end
exception EmptySignal
val neg = (op ~)
val swap = fn (x,v) => (case v of NONE => x | SOME v => v)
val equal = fn (x,y) => (x = y)
val signalOf = fn (v) => (case v of NONE => raise EmptySignal | SOME v => v)
val summer = fn (a,b) => (ListPair.map (fn (x,y) => x+y) (a,b))
val scaler = fn(a,lst) => (map (fn (x) => a*x) lst)
EOF
("val " ,solver ": (real list) stepper1 = make_" ,solver "()" ,nl)
("fun make_stepper (deriv) = " ,solver " (scaler,summer,deriv)" ,nl)
("fun integrate1d (f,h,x: real,y: real list) = ((make_stepper f) h) (x,y)" ,nl)
))
(define (name/Octave s)
(let ((cs (string->list (->string s))))
(let loop ((lst (list)) (cs cs))
(cond ((null? cs) (string->symbol (list->string (reverse lst))))
((null? (cdr cs))
(let ((c (car cs)))
(if (or (char-alphabetic? c) (char-numeric? c))
(loop (cons c lst) (cdr cs))
(loop (append (reverse (string->list (->string (gensym 't)))) lst) (cdr cs))
)))
(else
(let* ((c (car cs))
(c1 (cond ((or (char-alphabetic? c) (char-numeric? c)
(char=? c #\_)) c)
(else #\_))))
(loop (cons c1 lst) (cdr cs))))))))
(define (expr->Octave x . rest)
(let-optionals rest ((inner? #f))
(cases expr x
(E:Val (name v)
(if inner?
(list (name/Octave name) " = " (value->Octave v) )
(list (name/Octave name) " = " (value->Octave v) ";" nl)))
(E:Ife (test ift iff)
(list "if (" (value->Octave test) ") " nl
(expr->Octave ift ) nl
" else " (expr->Octave iff) " endif" nl))
(E:Let (bnds body)
(if inner?
(list #\[ (intersperse (map (lambda (x) (list "(" (expr->Octave x #t) ")"))
(append bnds (list body))) ", ") #\]
"(" (+ 1 (length bnds)) ")" nl)
(list (map (lambda (x) (list (expr->Octave x) nl)) bnds) nl
(expr->Octave body) nl)))
(E:Set (loc v)
(if inner?
(list (value->Octave loc) "(1) = " (value->Octave v))
(list (value->Octave loc) "(1) = " (value->Octave v) ";" nl)))
(E:Ret (v) (value->Octave v))
(E:Seq (exprs)
(list "[" (intersperse (map (lambda (x) (expr->Octave x #t)) exprs) ", ") "]"
"(" (length exprs) ")" nl))
(E:Noop () (list))
)))
(define (value->Octave v)
(cases value v
(V:C (v) v)
(V:Var (name) (name/Octave name))
(V:Rec (lst)
(list "struct (" (intersperse (map (lambda (nv) (list #\" (name/Octave (first nv)) #\" ", "
(value->Octave (cadr nv)))) lst) ", ") ")"))
(V:Sel (field v)
(list (value->Octave v) "." (name/Octave field)))
(V:Vec (lst)
(let ((n (length lst)))
(list "([" (intersperse (map (lambda (v) (value->Octave v)) lst) ", ") "])")))
(V:Sub (index v)
(list (value->Octave v) "((" index ")+1" ")"))
(V:Ldv (v)
(list "(" (value->Octave v) ")(1)"))
(V:Stv (v)
(list "[(" (value->Octave v) ")]"))
(V:Fn (args body)
(list "(@ (" (intersperse (map name/Octave args) ",") ") "
(expr->Octave body #t) ")"))
(V:Prim (name args)
(let* ((infix? (case name
((+ - * / >= > < <=) #t)
(else #f)))
(op name))
(cond ((null? args)
(case name
((NONE) (list name))
(else (list name "()"))))
((null? (cdr args))
(list op " (" (value->Octave (car args)) ")"))
((and infix? (null? (cddr args)))
(list "(" (value->Octave (car args)) ")" op "(" (value->Octave (cadr args)) ")"))
(infix?
(let ((op (case op ((+) 'sum) ((*) 'prod) (else op))))
(list op "([" (intersperse (map value->Octave args) ",") "])")))
(else
(list op "(" (intersperse (map value->Octave args) ",") ")")))))
(V:Ifv (test ift iff)
(list "((" (value->Octave test) ") && "
(value->Octave ift ) " "
" || " (value->Octave iff) ")"))
))
(define (prelude/Octave #!key (solver 'rk4b))
`(
#<