Interpreting multiple modules - chicken-scheme

I would like to have multiple modules in my program. Eg. module foo, and module bar. Module foo would refer to module bar. Then I would like to be able to test those modules in the csi (interpreted) repl. The root of this question is if I can run my code withouth having to compile it. Below is my example.
Note: I'm a scheme newbie, so there may be other issues with this code. Feel free to point anything out, and I will try to correct.
foo.scm
(use r7rs)
(define-library (foo)
(import (scheme base)
(prefix bar bar:))
(export add-some-stuff)
(begin
(define baz 1)
(define (add-some-stuff)
(+ baz bar:bork))
))
bar.scm
(use r7rs)
(define-library (bar)
(import (scheme base))
(export bork)
(begin
(define bork 2)))
Results would hope to be:
$ csi
> ,l foo.scm
> (import (prefix foo foo:))
> (foo:add-some-stuff)
;;=> 3
Here's the error I get:
$ csi -q
#;1> ,l foo.scm
; loading foo.scm ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/r7rs.import.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/chicken.import.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/numbers.import.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/foreign.import.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/srfi-4.import.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/scheme.base.import.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/r7rs-support.import.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/extras.import.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/srfi-13.import.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/r7rs-compile-time.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/r7rs-library.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/r7rs-support.so ...
Note: re-importing already imported syntax: syntax-rules
Note: re-importing already imported syntax: cond-expand
Note: re-importing already imported syntax: define-record-type
Note: re-importing already imported syntax: include
Note: re-importing already imported syntax: include
Note: re-importing already imported syntax: import
Note: re-importing already imported syntax: import-for-syntax
Note: re-importing already imported syntax: cond-expand
Note: re-importing already imported syntax: import-for-syntax
Note: re-importing already imported syntax: import
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/r7rs.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/numbers.so ...
; loading /usr/local/Cellar/chicken/4.12.0/lib/chicken/8/scheme.base.so ...
Note: re-importing already imported syntax: syntax-rules
Note: re-importing already imported syntax: import-for-syntax
Note: re-importing already imported syntax: import
Note: re-importing already imported syntax: cond-expand
Note: re-importing already imported syntax: import-for-syntax
Note: re-importing already imported syntax: import
Error: (import) during expansion of (import ...) - cannot import from undefined module: bar
Call history:
numbers.scm:1672: scan-real
<syntax> (define-library (foo) (import (scheme base) (prefix bar bar:)) (export add-some-stuff) (begin (defin...
<syntax> (##core#module foo ((##r7rs#foo)) (##core#define-syntax ##r7rs#foo (##core#lambda _ (quote (##core#u...
<syntax> (##core#define-syntax ##r7rs#foo (##core#lambda _ (quote (##core#undefined))))
<syntax> (##core#lambda _ (quote (##core#undefined)))
<syntax> (##core#begin (##core#quote (##core#undefined)))
<syntax> (##core#quote (##core#undefined))
<syntax> (##core#undefined)
<syntax> (##sys#provide (##core#quote foo))
<syntax> (##core#quote foo)
<syntax> (import-for-syntax (only r7rs begin cond-expand export import import-for-syntax include include-ci s...
<syntax> (##core#undefined)
<syntax> (import (only r7rs begin cond-expand export import import-for-syntax include include-ci syntax-rules...
<syntax> (##core#undefined)
<syntax> (##core#begin (import (scheme base) (prefix bar bar:)) (##core#begin (export add-some-stuff) (##core...
<syntax> (import (scheme base) (prefix bar bar:)) <--
#;1>

There's a few issues with this:
The syntax for loading the bar module is wrong, import expects a list of libraries, where (scheme base) would be one and (prefix bar bar:) would be another.
While the R7RS egg adds support for its module syntax, it reuses the existing module loading support which relies on having compiled modules to a shared library and an import library in a loadable location, like the egg repository or the current directory. You'll therefore have to compile both modules in the right order with csc -R r7rs -sJ before using them.
csc -R r7rs -sJ bar.scm succeeds, csc -R r7rs -sJ foo.scm doesn't. This is because the former invocation emits other-module.import.scm due to (define-library (other-module) ...). This needs to be changed to match the identifier you import it as.
With these changes I can reproduce your example session successfully. Here's a summary of the build steps and input files:
csc -R r7rs -sJ bar.scm
csc -R r7rs -sJ foo.scm
foo.scm
(use r7rs)
(define-library (foo)
(import (scheme base)
(prefix bar bar:))
(export add-some-stuff)
(begin
(define baz 1)
(define (add-some-stuff)
(+ baz bar:bork))
))
bar.scm
(use r7rs)
(define-library (bar)
(import (scheme base))
(export bork)
(begin
(define bork 2)))

Kooda from the #chicken irc channel recommended the system egg, and it seems to be doing what I'm looking for. In short, one needs to create a .system file that specifies the dependency tree, which is described below. It's a little unfortunate that Chicken Scheme can't figure out the internal module dependencies from looking at the import statements in each module, but I think this is the next best thing.
$ chicken-install system
create a file called so-question-chicken-scheme.system. That file should contain:
(define-system so-question-chicken-scheme
(scheme-file "bar")
(scheme-file "foo" depends: '("bar")))
Here's the interpreter results
$ csi -q
#;1> (use system)
#;2> (load "so-question-chicken-scheme.system")
#;3> (load-system so-question-chicken-scheme)
#;4> (import (prefix foo foo:))
#;5> foo:add-some-stuff
#<procedure (add-some-stuff)>
#;6> (foo:add-some-stuff)
3

Related

Compatibility with both Chez and Chicken Scheme

I'm trying to write a program compatible with both Chez and Chicken Scheme. Starting with something maximally simple:
(c1) R:\>type hello.ss
(display "hello, world\n")
(c1) R:\>csc hello.ss
(c1) R:\>hello
hello, world
(c1) R:\>"C:\Program Files\Chez Scheme 9.5.8\bin\a6nt\scheme.exe" --program hello.ss
Exception: invalid top-level program import subform (display "hello, world\n") at line 1, char 1 of hello.ss
Chicken is happy with the simplest version, but Chez isn't. Okay, I know a way to make Chez happy:
(c1) R:\>type hello2.ss
(import (rnrs))
(display "hello, world\n")
(c1) R:\>"C:\Program Files\Chez Scheme 9.5.8\bin\a6nt\scheme.exe" --program hello2.ss
hello, world
But does Chicken like that version?
(c1) R:\>csc hello2.ss
Syntax error (import): cannot import from undefined module
rnrs
Expansion history:
<syntax> (##core#begin (import (rnrs)))
<syntax> (import (rnrs)) <--
Error: shell command terminated with non-zero exit status 70: ""c:/chicken/bin/chicken.exe" "hello2.ss" -output-file "hello2.c""
Sadly, no.
How can I write a program that both implementations are happy with?

Symbols in chicken scheme egss don't get bound

Using chicken scheme, i installed some 'eggs', but when trying to use any procedure from them, the procedures name is never bound to an actual procedure. For example, on the csi interpreter:
#;1> (import glfw3)
#;2> (init)
Error: unbound variable: glfw3#init
The same thing happens with any procedure or value from any other 'egg' that I've tested, both in the interpreter and the compiler; nothing from any 'egg' ever gets bound.
Do you happen to be using CHICKEN 4? If so, you probably need (use glfw3) instead of (import glfw3). If you are using CHICKEN 5, (import glfw3) is correct and init should work.

How do I get this Chicken Scheme code to compile?

Apparently my previous question was too broad. So here's the question again, simplified, and with example source code.
I'm trying to compile a Chicken Scheme project containing multiple files:
test-a.scm:
#!/usr/bin/csi -script
(declare (unit test-a))
(declare (uses test-b))
(load "test-b.scm")
(use test-b)
(test-syntax)
test-b.scm:
(declare (unit test-b))
(module test-b *
(import scheme chicken)
(define-syntax test-syntax
(syntax-rules ()
((_)
(print "In test-syntax")))))
According to the official manual, I should do it like this:
csc -c test-b.scm
csc -c test-a.scm
csc test-a.o test-b.o -o test
What I actually get is this:
Syntax error (import): cannot import from undefined module
Things to note:
I'm calling a macro.
I have a (declare (uses clause, yet csc can't find my sources.
csc test-a.scm test-b.o -o test doesn't work either.
If I remove load, the program will not work in csi.
If I remove use, the program will not work in csi.
I need the program to work in csi.
How, without breaking compatibility with csi, can I make this compile?
There are four(!) problems here:
test-a.scm contains a unit declaration. This is incorrect; there's always one file that needs to be compiled to have a main() C function. That's the file without a unit declaration. If you study the manual page you linked more closely, it says "In this case foo.scm is the main module, because it doesn't have a unit declaration".
Since you decided to use modules, you'll need to compile test-b.scm as follows: csc -c -j test-b test-b.scm. The -j switch will cause the compiler to emit a module library test-b.import.scm, which is what the compiler is looking for when compiling test-a.scm. When an import library is missing, it will complain that the module is undefined. In the interpreter it's no issue because you load the file before importing the module that it defines.
You're using load, even in the compiled version of the program. This means that it will read and evaluate the test-b.scm file (and complain if it's missing) in every situation.
You're using use, which will require the library at runtime. This is meant for loading and importing modules defined by dynamically linked libraries.
So, to solve this, you could do it like this:
test-a.scm
#!/usr/bin/csi -script
;; Declare that this uses test-b, so that its toplevel is initialised
(declare (uses test-b))
;; No (declare (unit test-a)) because this file should generate main().
;; Because we tell the compiler what to link together and we want to
;; avoid passing all the .scm files on the csi command line, we can load
;; the test-b.scm file here, but only when interpreting:
(cond-expand
((not compiling) (load "test-b.scm"))
(else))
;; Only import the module; we take care of loading the code above,
;; or in the linking step when compiling. If we had (use test-b),
;; the library would be searched for at runtime.
;; Alternatively, (use test-b) here, but add (register-feature! 'test-b)
;; to test-b.scm, which prevents the runtime from attempting to load test-b.
(import test-b)
(test-syntax)
test-b.scm (unchanged)
(declare (unit test-b))
(module test-b *
(import scheme chicken)
(define-syntax test-syntax
(syntax-rules ()
((_)
(print "In test-syntax")))))
And, to compile it:
csc -c -j test-b test-b.scm
csc -c test-a.scm
csc test-a.o test-b.o -o test
I realise this is quite a lot of stuff to know, and tricky too and some things like the use plus register-feature! simply don't make much sense. We're attempting to make this less fiddly in CHICKEN 5, and we're also going to add a FAQ to the wiki, because this really isn't obvious and a bit of a FAQ.
The manual page you linked hasn't been changed in a long time: it completely ignores the existence of modules, for example. That's why you couldn't get it to compile, the -j switch was missing because the example files in the manual page don't define modules.
Edit:
This can be cleaned up a bit because declare is only honored by the compiler anyway. So we can move that into the cond-expand as well:
test-a.scm
#!/usr/bin/csi -script
(cond-expand
(compiling (declare (uses test-b)))
(else (load "test-b.scm")))
(import test-b)
(test-syntax)

Cannot work out how to run .scm (using guile or scm) files

I have created a abc.scm file and tried to compile it to a binary (or whatever guile scheme compiles to) using "guild compile", "scm" and "guile" commands in terminal in Ubuntu.
For "guild compile abc.scm", I get the output "wrote `/home/tarunmaganti/.cache/guile/ccache/2.0-LE-8-2.0/home/tarunmaganti/abc.scm.go'"
I find the file and run like this - "./abc.scm.go" which says permission denied.
When I give the necessary permissions using "chmod 755" or "chmod 777", I get an error like - "bash: ./abc.scm.go: cannot execute binary file: Exec format error".
The "scm whatever-file-name.scm" just opens up the scm interpreter.
The "guile whatever-file-name.scm does nothing.
The link of official GNU/Guile Scheme isn't very helpful.
Please, help me. I would like to create a guile scheme script file. Compile it and run it as C/C++ program. Is it possible?
If compilation isn't possible, I would like to know, how to at least run the script file of GNU/guile scheme or MIT-Scheme.
{Step-by-step is highly appreciated, I'm still a beginner in using Ubuntu and also in Scheme.}
Thanks in advance.
You can use the shebang notation to create a Guile script (the -s is optional in newer versions of Guile):
#!/usr/bin/guile -s
!#
(display "Hello, world!\n")
Notice the !# on the second line. Guile treats the #! as the start of a block comment (similar to what #| is in standard Scheme), which has to be terminated using !# (similar to |# in standard Scheme).
If you want your script to pass any command-line options to Guile itself, then read about the meta switch. Here's an example of such:
#!/usr/bin/guile \
-e main -s
!#
(define (main args)
(if (null? (cdr args))
(format #t "Hello, world!~%")
(for-each (lambda (name)
(format #t "Hello, ~a!~%" name))
(cdr args))))
Apparently guile foo assumes that foo is a Scheme source file. If foo is a precompiled binary .go file it tries to treat it as a text file anyway and compile it a second time, which fails. I could not find any equivalent command line syntax for executing a pre-compiled .go file.
However, you can get almost the same effect as follows:
Write a source file foo.scm that exports a main procedure:
(define-module (foo)
#:export (main))
(define (main)
(display "Hello world!")
(newline))
Pre-compile it with guild compile -o foo.go foo.scm
Write a shell script that runs guile -C "$PWD" -c "(use-modules (foo)) (main)". The -C dir flag (capital C) tells it to load pre-compiled files from the directory dir. The -c expr flag (lowercase c) tells it to evaluate the Scheme code expr which in this case just does use-module to load the pre-compiled module and then calls our main procedure.
Guile's compiler is like Java's compiler: it produces bytecode that is then run in Guile's VM. I don't know of any way to go straight from Guile Scheme code to native code. Guile is really meant to be an extension language that allows you to add Scheme scripting to your C/C++ program.
I don't know much about MIT Scheme, but from what I can tell it also does not compile to a standalone executable. Feel free to correct me on that.
There's a way around all this, though. As long as you don't mind a dependency on libguile, you can write a wrapper in C/C++ and hand libguile a string containing your Scheme code. There's a basic example given in the Guile manual for Dia here. Create your script in a header file and wrap it in a null-terminated C string, then (after a bit of boilerplate and whatnot) evaluate it with scm_eval_string().
If you want to write Scheme and output native binaries, I've heard good things about Chicken.

Compiling .scm files with MIT-SCHEME

Well, I'm trying to compile this simple scheme code using the "better" scheme interpreter/compiler MIT-SCHEME:
code.scm:
(declare (usual-integrations))
(define (s x) (* x x))
(display (s 2))
What am I doing? I'm doing this:
DXHJ ~ mit-scheme
DXHJ ~ (cf "code.scm")
;Generating SCode for file: "s.scm" => "s.bin"... done
;Compiling file: "s.bin" => "s.com"... done
;Unspecified return value
Well, after that I can't run anything. How can I generate an .out file?
It seems mit-scheme cannot compile to native, stand-alone binaries. There are other implementations that can do this. For example, Chicken scheme, Bigloo and gambit.

Resources