schemedoc / cookbook

New Scheme Cookbook
https://cookbook.scheme.org
29 stars 3 forks source link

Return type of the object #46

Closed jcubic closed 2 years ago

jcubic commented 2 years ago

I have this function in my interpreter, but it does a lot more since it also returns types for JavaScript objects and also internal implementation objects.

Here is something for R7RS scheme:

(define (type obj)
  (cond ((number? obj) "number")
        ((string? obj) "string")
        ((symbol? obj) "symbol")
        ((vector? obj) "vector")
        ((pair? obj) "pair")
        ((null? obj) "nil")
        ((procedure? x) "procedure")
        ((char? x) "character")
        ((boolean? obj) "boolean")))

Unfortunately, there is no way to test if an object is a record type.

@lassik Should we include functions like this or is it too simple? I think it would be nice to have this function so you don't need to write it yourself and can just copy/paste.

jcubic commented 2 years ago

A similar function is in #42 but that is more to match my implementation.

lassik commented 2 years ago

Sure, why not. It's a useful procedure. Since we divide the cookbook into sections, it should be quite easy to navigate even with lots of pages.

R7RS section 3.2. "Disjointness of types" lists all the standard predicates:

As you noticed, Scheme has no standard type-of procedure. Some implementations may have one, but I don't know what those are.

jcubic commented 2 years ago

@lassik in Guile and Chicken there are no bytevector? is there a way to make the function works if the function is defined and not?

Here is the code now:

(define (type obj)
  (cond ((number? obj) "number")
        ((pair? obj) "pair")
        ((null? obj) "nil")
        ((string? obj) "string")
        ((symbol? obj) "symbol")
        ((vector? obj) "vector")
        ((procedure? obj) "procedure")
        ((port? obj)
         (cond ((input-port? obj) "input-port")
               ((output-port? obj) "output-port")
               (else "unknown-port")))
        ((eof-object? obj) "eof")
        ((char? obj) "character")
        ((boolean? obj) "boolean")))
APIPLM commented 2 years ago

bytevector? is in the register-compiled-module of r7rs along with srfi-4 in the source /chicken-install/r7rs/r7rs.import.scm.

APIPLM commented 2 years ago

Unfortunatly seem like it is not in the document. As running ./chicken-doc bytevector? , the output is

path: (gl-utils bytevector?)

-- procedure:  (bytevector? BYTEVECTOR)

Returns true if `BYTEVECTOR` is a bytevector, false otherwise.

In the search result, there is not the path like (r7rs bytevector?) or (srfi-4 bytevector?)

lassik commented 2 years ago

bytevector? is in the (scheme base) library in R7RS.

In Chicken, using the r7rs egg with csi -R r7rs, (import (scheme base)) will import bytevector?.

SRFI 4 uses the term u8vector instead of bytevector. (import (srfi 4)) will provide u8vector?. In Chicken, bytevector? is an alias for u8vector?.

jcubic commented 2 years ago

We can include an alternative recipe with define-library.

APIPLM commented 2 years ago

@jcubic It is no needed, what we are talking about is that how chicken implementation bring the symbol bytevector? to in the (scheme base) library in R7RS. I supposed that in Chicken the waycsi -R r7rs,(import (scheme base)) is the standard to run any scheme script in R7RS, and that is part of running scheme script in R7RS in the Cookbook

lassik commented 2 years ago

@APIPLM Search for bytevector? in this file and you'll find the definition.

APIPLM commented 2 years ago

Thanks.@lassik I just checked that what REPL load sofiles are almost the same as running (import (scheme base) and (import r7rs). The only different is the loading additional r7rs.so file as running (import r7rs), but in the only file r7rs.scm is almost all about syntax. So basically in Chicken the standard way to run scheme script in R7RS is csi -R r7rs, or csi (import (scheme base)) . No need csi -R r7rs and (import (scheme base)), and csi -R r7rs and (import (scheme base)) are the same thing.

lassik commented 2 years ago

Yes, csi -R r7rs -s foo.scm is the way to run an R7RS script using Chicken. However, portable R7RS scripts should also start with (import (scheme base)).

lassik commented 2 years ago

@lassik in Guile and Chicken there are no bytevector? is there a way to make the function works if the function is defined and not?

In R7RS, and many non-R7RS Scheme implementations as well, that can be done with cond-expand:

(import (scheme base) (scheme write))

(cond-expand
 (r7rs
  (define type-of-alist-extra (list (cons bytevector? 'bytevector))))
 (else
  (define type-of-alist-extra '())))

(define type-of-alist
  (append type-of-alist-extra
          (list (cons boolean?    'boolean)
                (cons char?       'character)
                (cons eof-object? 'eof-object)
                (cons null?       'null)
                (cons number?     'number)
                (cons pair?       'pair)
                (cons port?       'port)
                (cons procedure?  'procedure)
                (cons string?     'string)
                (cons symbol?     'symbol)
                (cons vector?     'vector))))

(define (type-of obj)
  (let loop ((alist type-of-alist))
    (and (not (null? alist))
         (if ((caar alist) obj) (cdar alist) (loop (cdr alist))))))

(define (writeln x) (write x) (newline))

(writeln (type-of 123))
(writeln (type-of "abc"))
(writeln (type-of #\x))
(writeln (type-of (lambda (x) x)))
(writeln (type-of 'abc))
(writeln (type-of #(1 2 3)))
(writeln (type-of '(1 2 3)))
(writeln (type-of '()))
(writeln (type-of (eof-object)))
(writeln (type-of (current-input-port)))
(writeln (type-of (bytevector 1 2 3)))
jcubic commented 2 years ago

That is much better because you can extend the types easily, I wanted to create a dictionary with types but forget about Alist. I do too much JavaScript recently.

APIPLM commented 2 years ago

@lassik As we talked in the above, the standard way to run the top level script in Chicken is that ./csi -R r7rs -s foo.scm. But check with the r7rs-tools egg, it export two symbols eval , environment for the environment to run the script. But actually it just one ,it is environment. So what is its usage? Should it be in r7rs standard environment when running the top level script?

APIPLM commented 2 years ago

Sorry. r7rs egg just internally import scheme.eval, which have the symbols evaland environment. it does not export both symbols