Open lassik opened 3 years ago
For exporting static procedures to dynamic Scheme, I'd recommend just going with a normal (export ...)
in a define-static-library
. The type inference can figure out the type signature, so the export clause doesn't need to repeat the signature.
If we allow importing dynamic Scheme procedures into static libraries, as we probably should, the annotation must be hand-written somewhere. TypeScript has some system where they have auxiliary files (similar to Corba Interface Definition Language but simpler?) for dynamic JavaScript libraries to say what their types are.
I don't think you need a separate define-library
, not to say it is a bad idea, but what I imagined was:
(define-library (example static+dynamic)
(export a b)
(import (rename (steme)
(define define:)))
(begin
(define a 2) ; dynamic variable
(define: b (the integer 2)))) ; statically typed
(define-library (example static)
(export c)
(import (steme))
(begin
(define c 2))) ; static variable
So instead of a library being static or dynamic, the imported keywords and defined variables would be. Is there any disadvantage to this compared to declaring the library as static?
Yes, it may be enough to distinguish between exports with a well-defined type and all other exports, which cannot be imported into Steme without giving them explicit type annotations at the import level.
One reason why @lassik used the new keyword define-static-library
might be so that ordinary Scheme is not confused by seeing a define-library
form that, however, includes extensions that are only understood by Steme.
PS In your example, why wouldn't a
be a statically typed variable? The type can obviously be easily inferred.
PPS Long before we finalize the library system, we should get the type system at the expression level done.
Continuing from https://github.com/pre-srfi/static-scheme/issues/11#issuecomment-723340472
(define-static-library-from-dynamic (scheme set)
(import (static base)
(static set)
(static comparator))
(export (set-intersection (-> (set a) (set a) (set a)))
(set-xor (-> (set a) (set a) (set a)))
(set-map (-> (comparator b) (-> a b) (set a)))))
(define-static-library (example)
(import (static base)
(static vector)
(scheme set))
...)
The more different scenarios I think through, the better it seems to have all the static code confined into static libraries, and to have all the FFI definitions in separate interface libraries. The static code is supposed to be purer than the dynamic code, and the FFI will be messy by comparison no matter how it's done. The same guarantees about type inference and type checking don't hold. It just seems clearest to separate the fundamentally different stuff. No matter how convenient c-lambda
is in Gambit...
Using a library granularity for the time being, there should probably be three top-level forms:
(define-library ...)
-- dynamic Scheme library as in R7RS; the equivalent is(library ...)
in R6RS(define-static-library ...)
-- statically typed library(define-static+dynamic-library ...)
-- small domain-specific language importable to both Scheme and StemeThe static+dynamic DSL would allow defining at least the following things: