Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 01:12
    feeley commented #802
  • 00:32
    CI run 3634097312 passed
  • Dec 06 22:42

    gambiteer on master

    Special-case exact 0 dividend f… (compare)

  • Dec 06 05:07
    rogera47 commented #803
  • Dec 05 23:01
    gambiteer commented #803
  • Dec 05 22:47
    rogera47 commented #803
  • Dec 05 20:02
    CI run 3622976890 passed
  • Dec 05 18:42
    gambiteer commented #803
  • Dec 05 18:37

    gambiteer on master

    Add SRFI 141 support Add SRFI 141 to makefile (compare)

  • Dec 05 05:30
    rogera47 opened #803
  • Dec 05 03:29
    feeley commented #802
  • Dec 05 02:25
    gambiteer commented #802
  • Dec 05 01:31
    feeley commented #802
  • Dec 04 16:54
    Linux build of CI run 3614175140 failed
  • Dec 04 16:48

    gambiteer on master

    Adjust unit tests for SRFI 141 … Add R7RS large/SRFI 141 divisio… Test division operators with ar… and 3 more (compare)

  • Dec 04 16:48
    gambiteer closed #802
  • Dec 04 16:22
    gambiteer synchronize #802
  • Dec 04 15:41
    dpk commented #675
  • Dec 04 15:40
    dpk commented #675
  • Dec 04 15:40
    dpk commented #675
Marc Feeley
@feeley
Ah yes, that’s an old Gambit… -h and --help were added a few years ago...
felix-lipski
@felix-lipski
okay, works with a newer version, thanks!
KM
@twoplustwo:matrix.org
[m]
Hello :) I am trying to understand what the 'rest' arguments are in 6.2 "6.2 Extensions to standard special forms" iro.umontreal.ca/~gambit/doc/gambit.html#Extensions-to-standard-special-forms - how are they different from optionals and what are they used for?
Marc Feeley
@feeley

@twoplustwo:matrix.org Take number->string… the first parameter (a number) is required, and the second parameter is optional (a number that is the base) and you cannot pass more than 2 parameters:

> (number->string 42)
"42"
> (number->string 42 2)
"101010"
> (number->string 42 2 111 222 333)
*** ERROR IN (stdin)@3.1 -- Wrong number of arguments passed to procedure
(number->string 42 2 111 222 333)

But sometimes you want to accept any number of parameters, for example the - procedures requires one parameter, but can have any number of additional parameters:

> (- 5)
-5
> (- 5 2)
3
> (- 5 2 1)
2
> (- 5 2 1 111 222 333)
-664

For this situation you need to define the procedure using a rest parameter which will be a list of all the remaining parameters:

> (define (- first . rest) (list 'first= first 'rest= rest))               
> (- 5)
(first= 5 rest= ())
> (- 5 2 1 111 222 333)                                     
(first= 5 rest= (2 1 111 222 333))
KM
@twoplustwo:matrix.org
[m]
Oh and I can just use a dot instead of #!optional. thanks a lot!
This makes perfect sense to me now
Marc Feeley
@feeley
no… the . is the same as #!rest#!optional marks the beginning of optional parameters
> (define (a x y #!optional z) (list 'x= x 'y= y 'z= z))
> (define (b x y #!optional z #!rest rest) (list 'x= x 'y= y 'z= z 'rest= rest))
> (a 1 2)
(x= 1 y= 2 z= #f)
> (a 1 2 3)
(x= 1 y= 2 z= 3)
> (a 1 2 3 4)
*** ERROR IN (stdin)@5.1 -- Wrong number of arguments passed to procedure
(a 1 2 3 4)
1> ,t
> (b 1 2)
(x= 1 y= 2 z= #f rest= ())
> (b 1 2 3)
(x= 1 y= 2 z= 3 rest= ())
> (b 1 2 3 4)
(x= 1 y= 2 z= 3 rest= (4))
> (b 1 2 3 4 5)
(x= 1 y= 2 z= 3 rest= (4 5))
KM
@twoplustwo:matrix.org
[m]
oh yesm of course, I mixed it up ;)
cs7
@cs7:matrix.org
[m]
KM: "." is R5RS, #!rest #!optional #!key is DSSSL = some extension
KM
@twoplustwo:matrix.org
[m]
so there is no need for the extension when I only use rest. is there also a way to use keywords without dsssl ? lets say (define (h1 a #!rest r #!key k) (list a k r)) is this possible?
Marc Feeley
@feeley
> (define (foo x #!key y z . rest) (list 'x= x 'y= y 'z= z 'rest= rest))
> (foo 1)                                                               
(x= 1 y= #f z= #f rest= ())
> (foo 1 z: 2)
(x= 1 y= #f z= 2 rest= ())
> (foo 1 z: 2 y: 3)
(x= 1 y= 3 z= 2 rest= ())
> (foo 1 z: 2 y: 3 4)
(x= 1 y= 3 z= 2 rest= (4))
> (foo 1 z: 2 y: 3 4 5)
(x= 1 y= 3 z= 2 rest= (4 5))
KM
@twoplustwo:matrix.org
[m]
tried it in the repl, this is so cool
cs7
@cs7:matrix.org
[m]
KM: Stuff you learn (that wasn't obvious before you learned it), write it up on the wiki, someone else will probably has the same question later
cs7
@cs7:matrix.org
[m]
:point_up: Edit: KM: Stuff you learn (that wasn't obvious before you learned it), write it up on the wiki, someone else will probably have the same question later
KM
@twoplustwo:matrix.org
[m]
Is there a good way to replace strings in templates, like replace all {{key1}} {{key2}} with value1 valu2 in a string or maybe in a textfile?
Or if not, I could write my own, but how do I find a string position inside another one?
KM
@twoplustwo:matrix.org
[m]
I found this string-contains here https://practical-scheme.net/wiliki/schemexref.cgi?string-contains can I use it somehow?
Marc Feeley
@feeley
@twoplustwo:matrix.org This could be useful:
(define (string-substitute str delim proc-or-alist)

  (define (index-of c start)
    (let loop ((i start))
      (if (fx< i (string-length str))
          (if (char=? c (string-ref str i))
              i
              (loop (fx+ i 1)))
          i)))

  (let loop ((i 0) (j 0) (out '()))
    (let ((start (index-of delim j)))
      (if (fx< start (string-length str))
          (let ((end (index-of delim (fx+ start 1))))
            (if (fx< end (string-length str))
                (if (fx= start (fx- end 1)) ;; two delimiters in a row?
                    (loop (fx+ end 1)
                          (fx+ end 1)
                          (cons (substring str i end)
                                  out))
                    (let* ((var
                            (substring str (fx+ start 1) end))
                           (subst
                            (if (procedure? proc-or-alist)
                                (proc-or-alist var)
                                (let ((x (assoc var proc-or-alist)))
                                  (and x (cdr x))))))
                      (if subst
                          (loop (fx+ end 1)
                                (fx+ end 1)
                                (cons subst
                                        (cons (substring str i start)
                                                out)))
                          (error "Unbound substitution variable in" str))))
                (error "Unbalanced delimiter in" str)))
          (string-concatenate
           (reverse (cons (substring str i start) out)))))))

(pp (string-substitute "@a@ plus 1 is @b@" #\@ '(("a" ."two") ("b" . "three"))))
KM
@twoplustwo:matrix.org
[m]
cool, I will walk through this. how can I import string-concatenate ?
Marc Feeley
@feeley
@twoplustwo:matrix.org string-concatenate is builtin (you need v4.9.4)
cs7
@cs7:matrix.org
[m]
= same as string-append ?
Marc Feeley
@feeley
@twoplustwo:matrix.org (string-concatenate lst) = (apply string-append lst)
cs7
@cs7:matrix.org
[m]
ah yesyes i see. many thanks.
jeffhhk
@jeffhhk

Hello, I'm trying gambit for the first time, starting with the javascript support in 4.9.4. I am able to reproduce the instructions at

http://www.gambitscheme.org/latest/manual/#Compiling-Modules

However, if I change much from that basic scenario, stuff stops working. For example, here is my attempt to extend to importing SRFI 78:

git clone https://github.com/scheme-requests-for-implementation/srfi-78

cat srfi-78/srfi-78.sld
    (define-library (srfi-78)
      (import (scheme base))
      (export hello-world)
      (include "check.scm")
      (begin
        (define (hello-world)
          (display "hello world\n"))
    ))

cat hello-test/hello-test.sld
    (define-library (hello-test)
      (import (srfi-78) (scheme base) (scheme write))
      (begin
        (display
         (cond-expand
           ((compilation-target C)   "compiled to C\n")
           ((compilation-target (_)) "interpreted\n")
           (else                     "compiled to other\n")))
        (hello-world)
        (newline)))

gsc -target js . srfi-78 hello-test
    Building module: srfi-78

gsc -target js . srfi-78
    <no output>
gsc -target js . hello-test
    <no output>

gsc -target js -exe -nopreload . srfi-78/srfi-78.sld hello-test/hello-test.sld
    srfi-78/srfi-78.sld:
    /home/jeff/srchome/src/zipper/srfi-78/srfi-78.js:
    hello-test/hello-test.sld:
    /home/jeff/srchome/src/zipper/hello-test/hello-test.js:
    /home/jeff/srchome/src/zipper/hello-test/hello-test_.js:

hello-test/hello-test
    compiled to other
    *** ERROR IN hello-test# -- Operator is not a PROCEDURE
    (#!void "hello world\n")
I would have expected:
  • two "Building module" messages for building srfi-78 and hello-test together
  • one "Building module" message for building srfi-78 and hello-test each separately
  • successful -exe generation to result in a runnable program.
Results are the same with or without the (include "check.scm") commented out.
jeffhhk
@jeffhhk
Thanks in advance for any help!
jeffhhk
@jeffhhk
Well I figured out one thing:
(define-library (srfi-78)
  (import (scheme base) (scheme write))

Now:

gsc -target js . srfi-78 hello-test && \
gsc -target js -exe -nopreload . srfi-78/srfi-78.sld hello-test/hello-test.sld && \
node hello-test/hello-test

emits:

Building module: srfi-78
srfi-78/srfi-78.sld:
/home/jeff/srchome/src/zipper/srfi-78/srfi-78.js:
hello-test/hello-test.sld:
/home/jeff/srchome/src/zipper/hello-test/hello-test.js:
/home/jeff/srchome/src/zipper/hello-test/hello-test_.js:

compiled to other
hello world
jeffhhk
@jeffhhk

So that's good. Still can't get these:

(export hello-world check)
(include "check.scm")

To allow this:

(check (+ 2 2) => 4)
Ok, this did the trick:
(define-library (srfi-78)
  (import (scheme base) (scheme write))
  (export hello-world check check-passed? check-report check-reset! check-set-mode!
    check:add-correct! check:add-failed! check:correct check:failed
    check:mode check:proc check:proc-ec check:report-actual-result
    check:report-correct check:report-expression check:report-failed
    check:write)
  (include "check.scm")
  (begin
    (define (hello-world)
      (display "hello world\n"))
))
I think I've answered my question. Thanks!
Marc Feeley
@feeley
@jeffhhk Yes the macro dependencies are not automatically exported (as they should be implicitly)… this is being worked on
BTW the -warnings option to gsc is useful in this situation
jeffhhk
@jeffhhk
@feeley Good to know, thanks!
jeffhhk
@jeffhhk

I'm looking for a workflow to incrementally develop a library in the r7rs define-library style, including the ability to test in a repl. Currently using emacs scheme-mode for sending to the repl.

Suppose I want to change the library and then as quickly as possible test with the repl. I wrote a wrapper script to run gsi which finds the correct directory to pass with -:search so that my import will work. But after making a change I noticed when doing import as above in gsi that I can't seem to do import again and pick up the change. I'm okay with clearing out my environment to do so.

  • I tried finding a clear scheme environment api, but didn't see one.
  • I tried passing -prelude "(import (my-lib))" to get a gsc repl, but gsc doesn't evaluate display statements before dropping to the repl.
  • I tried passing -prelude "(import (my-lib))" to gsi, but gsi seems to reject it outright.

I suppose I could script this with a custom emacs command or subprocess tty hacks, but I was hoping to stay within gambit for editor independence. Is there any similar api available?

jeffhhk
@jeffhhk
Here's an attempt to use .gambini to do a project-specific repl initial import:
(display "hello $HOME/.gambini\n")

(define (dir-for-project)
  (let loop ((d (path-strip-trailing-directory-separator (current-directory))))
    (let ((files (directory-files (list (string->keyword "path") d (string->keyword "ignore-hidden") #f))))
      (if (or (equal? 0 (string-length d))
          (member ".gambini-local" files))
      d
      (loop (path-strip-trailing-directory-separator (path-directory d)))))))

(map display `(about to add ,(dir-for-project) "\n"))
(module-search-order-add! (dir-for-project))

;; TODO: look for project-specific modules to load in .gambini-local

;; For now, simulate by hard-coding:

;;(import (srfi-78))
;;  =>
;;  Cannot find library (srfi-78)
(eval "(define foo 123)")
;; does not cause error, but foo is not bound in the repl
Marc Feeley
@feeley
@jeffhhk you probably want:
$ gsi . -e "(import (srfi 28))" -
> (format "~a + ~a = ~a" 1 2 3)
"1 + 2 = 3"
and for eval you want: (eval ‘(define foo 123))
because (eval “a string”) => ”a string”
Marc Feeley
@feeley
This undocumented feature may also be useful:
$ gsi
Gambit v4.9.4-39-g9a887b80

> (import foo/bar) ;; same as (import (foo bar))
> (##remove-registered-module ‘foo/bar)
...
> (import foo/bar) ;; will load it again
jeffhhk
@jeffhhk
Great thanks! All useful. Here it is all put together:
#|
Initializes project-specific path and imports for repl-based testing.
Place initialization code for your gambit based project in the project
root directory.

For example:
    mkdir -p srfi-78
    git clone https://github.com/scheme-requests-for-implementation/srfi-78 srfi-78/srfi-78
    cat > srfi-78/srfi-78.sld 
        (define-library (srfi-78)
          (import (scheme base) (scheme write))
          (export hello-world check check-passed? check-report check-reset! check-set-mode!
            check:add-correct! check:add-failed! check:correct check:failed
            check:mode check:proc check:proc-ec check:report-actual-result
             check:report-correct check:report-expression check:report-failed
            check:write)
          (include "srfi-78/check.scm")
          (begin
            (define (hello-world)
              (display "hello world\n"))
        ))
    cat > .gambini-local
        (import (srfi-78))
        (define bar 456)
    gsi
        hello HOME/.gambini
        Found .gambini-local.  Will module-search-order add ../src/zipper
        About to eval: (begin (import (srfi-78)) (define bar 456))
        Gambit v4.9.4

        > bar
        456
        > (check (+ 2 2) => 4)

        (+ 2 2) => 4 ; correct
        >     
|#
(import (srfi 28))

(define rfile-local ".gambini-local")

(define (dir-for-project)
  (let loop ((d (path-strip-trailing-directory-separator (current-directory))))
    (let ((files (directory-files (list (string->keyword "path") d (string->keyword "ignore-hidden") #f))))
      (cond
       ((equal? 0 (string-length d)) #f)
       ((member rfile-local files) d)
       (else 
    (loop (path-strip-trailing-directory-separator (path-directory d))))))))

(define (file-for-project)
  (path-expand rfile-local (dir-for-project)))

(if (dir-for-project)
    (begin
      (display (format "Found .gambini-local.  Will module-search-order add ~a\n" (dir-for-project)))
      (module-search-order-add! (dir-for-project))

      (let ((sexp-local `(begin ,@(with-input-from-file ".gambini-local" (lambda () (read-all (current-input-port)))))))

    (display (format "About to eval: ~a\n" sexp-local))
    (eval sexp-local))))
jeffhhk
@jeffhhk

A curious thing about the above .gambini is that it runs even when initializing gsc for batch compilation. Is there an API for detecting running in a repl, such as cond-expand?

If not, I suppose I could guard the above with an environment variable and only set it in my testing repl.

Marc Feeley
@feeley

@jeffhhk The Gambit manual has this explanation:

Extensions which are meant to apply to a single user or to a specific working directory are best placed in the initialization file, which is a file containing Scheme code. In all modes, the interpreter first tries to locate the initialization file by searching the following locations: ‘.gambini’ and ‘ ̃/.gambini’ (with no extension, a ‘.sld’ extension, a ‘.scm’ extension, and a ‘.six’ extension in that order). The first file that is found is examined as though the expression (include initialization-file) had been entered at the read-eval-print loop where initialization-file is the file that was found. Note that by using an include the macros defined in the initialization file will be visible from the read-eval-print loop (this would not have been the case if load had been used). The initialization file is not searched for or examined when the ‘-f’ option is specified.

The .gambini file will be visited by gsi and gsc (unless the -f option is specified) because the code it contains is meant to configure or extend the Gambit runtime library. There are various ways to detect if code is being run by gsi or gsc:
1) check for presence of compile-file procedure which is defined only by gsc:

(if (##unbound? (##global-var-ref (##make-global-var 'compile-file)))
    (display “gsi\n”)
    (display “gsc\n”))

2) check the name of the executable:

(if (member (path-strip-directory (executable-path)) '("gsi" "gsi-script”))
    (display “gsi\n”)
    (display “gsc\n”))

3) if you want to check if code is interpreted or compiled:

$ cat .gambini
(define-macro (interpreted-code?)
  `(cond-expand ((compilation-target (_))
                 #t)
                (else
                 #f)))
$ cat foo.scm
(if (interpreted-code?)
    (display "interpreted code\n")
    (display "compiled code\n"))
$ gsi foo.scm
interpreted code
$ gsc -exe foo.scm
$ ./foo
compiled code
$ gsc -i foo.scm
interpreted code
$ gsc
Gambit v4.9.4-39-g9a887b80

> (load "foo.scm")
interpreted code
"/Users/feeley/foo.scm"
> (compile-file "foo.scm")
"/Users/feeley/foo.o1"
> (load "foo.o1")
compiled code
"/Users/feeley/foo.o1"

Note that with #3 it is not the program (gsi or gsc) that is checked, but rather the way the code is executed, which is often a more robust test because gsc can both compile and interpret code (when given the -i option or no command line arguments).

1 reply
Ricardo G. Herdt
@r.herdt_gitlab

Hi there!
While porting my json-rpc to Gambit, I found a possible bug:

> (alist->hash-table '())
*** ERROR IN (stdin)@2.1 -- PAIR LIST expected
(srfi/69#alist->hash-table '())

Trying to convert an empty list into a hash-table sounds lame, but I'm using it as a set-filter for make-parameter, like this:

(define json-rpc-handler-table
  (make-parameter '() (lambda (alist) (alist->hash-table alist equal?))))

I'm using v4.9.4. BTW, I also noticed that gsi still shows v4.9.3

Ricardo G. Herdt
@r.herdt_gitlab
another bug: define-values seems not to work inside a lambda/function definition. According to R7RS define-values "is allowed wherever define is allowed":
> (define (f) (define-values (a b) 1 2) #t)     
*** ERROR IN (stdin)@2.13 -- Unknown expression parsing exception
Marc Feeley
@feeley
The bug with SRFI 69 is kind of embarassing… now fixed and I have added unit tests for this.
Concerning the problem with define-values, the correct implementation of this form and other R7RS forms depends on the new macro system we are working on… in the meantime you can use this definition:
(define-macro (define-values vars expr)
  (cond ((null? vars)
         (let ((temp (gensym)))
           `(##define ,temp
              (##call-with-values (##lambda () ,expr) ##list))))
        ((null? (cdr vars))
         `(##define ,(car vars) ,expr))
        (else
         (let ((temp (gensym)))
           `(##begin
              (##define ,temp
                (##call-with-values (##lambda () ,expr) ##list))
              ,@(map (lambda (var)
                       `(##define ,var
                          (##if (##pair? ,temp)
                                (##let ((val (##car ,temp)))
                                  (##set! ,temp (##cdr ,temp))
                                  val)
                                (##error "too few values"))))
                     vars))))))
Ricardo G. Herdt
@r.herdt_gitlab
Thanks Marc!
Mark Friedman
@mark-friedman

In the "try" IDE, I'd like to change the orientation of the console and editor panes from horizontal to vertical, i.e. have the console on top of the editor. I thought that maybe just changing UI.js:59 from:

  elem.classList.add('g-h-panes');

to

  elem.classList.add('g-v-panes');

might suffice, but no such luck. I end up just seeing the console. Most all of the class/style stuff seems to be nicely abstracted but I'm guessing that there is an assumption built somewhere in there (maybe the CSS) that is breaking it. Any guidance would be appreciated. My CSS-fu is not strong.

Thanks.