Giter Club home page Giter Club logo

husk-scheme's People

Contributors

bholst avatar egisatoshi avatar farrellm avatar joshtriplett avatar justinethier avatar nakayama900 avatar natethern avatar svenkeidel avatar travitch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

husk-scheme's Issues

API documentation

Future enhancement: API documentation (xDoc) generated for all built-in functions. Ideally the docs would also link to reference documentation for language keywords.

Improper list in macro pattern not matched when input is a list

Consider the following macro and test code:

(define-syntax when
(syntax-rules ()
((when condition . body) (if condition (begin . body) #f))))
;((when condition body ...) (if condition (begin . body) #f))))

(define x -1) 
(when (negative? x)
      (newline)
      (display "bad number: negative"))

The output when run with original version of above is (with debug traces):

huski> (load "scm-unit-tests/test 
         test.scm   test2.scm
         huski> (load "scm-unit-tests/test.scm" )
         loadLocal pattern = ((condition . body)) input = ((negative? x) (newline) (display "bad number: negative"))
         loadLocal pattern = (condition . body) input = (negative? x)
         loadLocal pattern = (condition body ...) input = (negative? x)
         loadLocal pattern = (body ...) input = (x)
         loadLocal pattern = (body ...) input = ()
         loadLocal pattern = () input = ((newline) (display "bad number: negative"))
         Input does not match a macro pattern: (when (negative? x) (newline) (display "bad number: negative"))

Output when using the ... above instead of a pair:

huski> (load "scm-unit-tests/test.scm" )
    loadLocal pattern = (condition body ...) input = ((negative? x) (newline) (display "bad number: negative"))
    loadLocal pattern = (body ...) input = ((newline) (display "bad number: negative"))
    loadLocal pattern = (body ...) input = ((display "bad number: negative"))
    loadLocal pattern = (body ...) input = ()

"bad number: negative" 

The output clearly shows that the problem is that by the time we get to inserting the ... in the pattern, we have already moved too far into the input. Perhaps the pattern matcher needs to search for the pattern List[DottedList] instead of searching for dotted lists directly. Need to be careful here...

Internal procedures are not directly exposed to interpreter environment

Procedures that are built into the evaluator are not directly exposed. For example, in bigloo the apply function can be referenced directly:

1:=> apply
#<procedure:295740.-3>
1:=> (procedure? apply)
#t

On husk this currently results in an error:

huski> apply
Getting an unbound variable: apply
huski> (procedure? apply)
Getting an unbound variable: apply

Many functions are affected, including:

  • apply
  • call-with-current-continuation
  • call/cc (which should be part of stdlib with this change)
  • others?

Example programs for file and network I/O

Example programs should be provided to demonstrate how husk can be used to perform file I/O and network I/O. Husk internals may need to be modified (per spec) on an as-needed basis to support this.

N-ary macros

From http://eval.apply.googlepages.com/eccentric.txt -

By using a dotted tail in the pattern we can write macros that take an
arbitrary number of arguments.

(define-syntax when
(syntax-rules ()
((when condition . body) (if condition (begin . body) #f))))

An example usage is

(when (negative? x)
   (newline)
   (display "Bad number:  negative."))

The pattern matches as follows:

condition = (negative? x)

body = ((newline) (display "Bad number: negative."))

Since the pattern variable `body' is in the dotted tail position, it
is matched against the list of remaining elements in the form. This
can lead to unusual errors.

...

*** Implicit Begin idiom

Use this idiom for a macro that allows an arbitrary number of
subforms and processes them sequentially (possibly returning the
value of the last subform).

The pattern should end in "FORM . FORMS)" to ensure a minimum of
one subform.

The template has either (begin form . forms) or uses the implicit
begin of another special form, e.g. (lambda () form . forms)

Provide call history when an error is thrown

It would be nice to have some form of call history printed when an error occurs, so the user has more information to track down the problem. As it is now, by just printing the error itself it is difficult to isolate what Scheme code may have caused the problem.

Define should save a memory location for mutable data types

Define should save a reference to objects, for example try the following code in husk and another Scheme:

(define x (list 'a 'b 'c))
(define y x)
(set-cdr! x 4)
; y should be (a . 4) but it is still (a b c)

There are 3 test cases this fails in t-stdlib.scm

Also consider the following test case, where an object is passed to a different scope:

(define vec (make-vector 2 #f))
((lambda (v) (vector-set! v 1 3)) vec)
(write vec)

vec should be modified at the end, but it is still #(#f #f).


The more general problem here is that there are certain data types that can be modified if an instance is passed directly to a mutator such as set! or set-cdr!. This is discussed specifically in section 3.4 Storage Model:

Variables and objects such as pairs, vectors, and strings implicitly denote locations or sequences of locations. A string, for example, denotes as many locations as there are characters in the string. (These locations need not correspond to a full machine word.) A new value may be stored into one of these locations using the string-set! procedure, but the string continues to denote the same locations as before.

An object fetched from a location, by a variable reference or by a procedure such as car, vector-ref, or string-ref, is equivalent in the sense of eqv? (section 6.1) to the object last stored in the location before the fetch.

Every location is marked to show whether it is in use. No variable or object ever refers to a location that is not in use. Whenever this report speaks of storage being allocated for a variable or object, what is meant is that an appropriate number of locations are chosen from the set of locations that are not in use, and the chosen locations are marked to indicate that they are now in use before the variable or object is made to denote them.

In many systems it is desirable for constants (i.e. the values of literal expressions) to reside in read-only-memory. To express this, it is convenient to imagine that every object that denotes locations is associated with a flag telling whether that object is mutable or immutable. In such systems literal constants and the strings returned by symbol->string are immutable objects, while all objects created by the other procedures listed in this report are mutable. It is an error to attempt to store a new value into a location that is denoted by an immutable object.

These mutable data types are:

  • String
  • Pair
  • List
  • Vector
  • HashTable

Division does not properly convert to other numeric types

The following test case fails, because internally husk perform an integer operation:

(assert/equal (/ 3 4 5)     3/20)

Scheme should handle this by converting up to a rational, or at least a floating-point type. For example, in chicken (/ 1 2) evaluates to 0.5, whereas (/ 2 1) evaluates to an exact value of 2.

Simplification of improper lists

The following quoted expression is simplified in other implementations such as Chicken:

'(1 2 . (3 . ()))
=> (1 2 3)

husk should do this a well.

In certain cases, macro transformations do not properly distinguish between pairs and lists

When a pair is present in a macro transformation, that transformation does not always agree with transformation of the same code by a reference implementation (Chicken Scheme):

(define-syntax my-pair-test/06
  (syntax-rules ()
     ((_ var . step)
      (list (quote (var . step))))))

(write (my-pair-test/06 (1 . 3)))
; outputs: ((1 3))
; reference implementation (chicken) outputs (((1 . 3)))
(write (my-pair-test/06 (1 2)))
; outputs: ((1 2))

More investigation is required to determine exactly what the problem is, if any.
There are many test cases in t-macro.scm that fail due to this issue.

Nested quasiquotation forms are not handled properly

Nested ` forms must be handled properly, as per spec:

  • Quasiquote forms may be nested.
  • Substitutions are made only for unquoted components appearing at the same nesting level as the outermost backquote.
  • The nesting level increases by one inside each successive quasiquotation, and decreases by one inside each unquotation.

For example, the form

`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)           

Should evaluate to the following, because (+ 1 3) is at the same depth level as the outer backtick:

(a `(b ,(+ 1 2) ,(foo 4 d) e) f)

However, this form throws an error instead because husk does not presently respect depth level when evaluating quasi-quoted forms.

Add a gensym primitive

The semantics of this function should be similar to those from other Schemes, EG:

Finally, some applications, especially those that generate new Scheme code dynamically, need to generate symbols for use in the generated code. The gensym primitive meets this need:

— Scheme Procedure: gensym [prefix]
— C Function: scm_gensym (prefix)

Create a new symbol with a name constructed from a prefix and a counter value. The string prefix can be specified as an optional argument. Default prefix is ‘ g’. The counter is increased by 1 at each call. There is no provision for resetting the counter.

(and) / (or) operations do not follow spec

Neither of these operations properly conforms to the spec - see corresponding test cases in t-stdlib.scm for examples.

Basically, each operation should accept any value, not just booleans:

The expressions are evaluated from left to right, and the value of the first expression that evaluates to a false value (see section 6.3.1) is returned. Any remaining expressions are not evaluated. If all the expressions evaluate to true values, the value of the last expression is returned. If there are no expressions then #t is returned.

For example:

(assert/equal (and 1 2 'c '(f g))     '(f g))

numerator and denominator do not accept real numbers

From the spec:

These procedures return the numerator or denominator of their argument; the result is computed as if the argument was represented as a fraction in lowest terms. The denominator is always positive. The denominator of 0 is defined to be 1.

However, these functions do not accept real (floating point) numbers as an argument. For example:

huski> (denominator 1/2)
2
huski> (denominator 0.5)
Invalid type: expected rational number, found 0.5
huski> (numerator 0.5)
Invalid type: expected rational number, found 0.5

Invalid vector forms are allowed

In chicken:

#;1> #(a)
Error: illegal non-atomic object: #(a)
#;1> #((+ 2 3))
Error: illegal non-atomic object: #((+ 2 3))

The same forms in husk:

huski> #(a)
#(a)
huski> #((+ 2 3))
#((+ 2 3))

Flagging of unmatched variables does not distinguish between lists and pairs

Consider the following example:

(define-syntax pair-test-00
  (syntax-rules ()
     ((_ (a b . c))
      (quote (a b c)))))

(assert/equal (pair-test-00 (1 2)) '(1 2 ()))

This should transform into (1 2 ()) but instead it becomes (1 2). This is because the code in flagUnmatchedVars needs to keep track of whether or not a flagged variable (c in this case) was part of a match as part of an ellipsis ... or as the last member of an improper list (pair). This could probably be done using an array of booleans, much as it is handled in the rest of the pattern matching code.

Once this flag is stored, the transform code needs to take it into account when it encounters an "unmatched" variable.

Move FFI into it's own module

The FFI code should be moved into its own module. This would isolate it and should allow Core to be debugged via ghci.

husk does not build on GHC 7

Tested using ghc version 7.0.2 on Fedora 15.
The compile output is:

[7 of 9] Compiling Language.Scheme.Core ( hs-src/Language/Scheme/Core.hs, hs-src/Language/Scheme/Core.o )

hs-src/Language/Scheme/Core.hs:738:31:
Couldn't match expected type (GHC.Module, Maybe (GHC.ImportDecl GHC.RdrName))' with actual typeGHC.Module'
In the expression: m
In the second argument of GHC.setContext', namely[m]'
In a stmt of a 'do' expression: GHC.setContext [] [m]
make: *** [husk] Error 1

Low Level macro support

Low-level macros should be available via a standard system such as syntatic closures or explicit renaming - er-macro-transformer

High and low-level support via syntax-case would be nice, but is probably too complicated to implement at this time (or maybe ever). Anyway, see: http://srfi.schemers.org/srfi-72/srfi-72.html

Parentheses missing in macro transform

Consider the following macro:

(define-syntax my-pair-test/06
(syntax-rules ()
((_ var . step)
(list (quote (var . step))))))

An extra pair of parens needs to be added around the match; currently the following test cases are failing by not including one level of outer parentheses:

(assert/equal (my-pair-test/06 (1 . 3))
'(((1 . 3))))
(assert/equal (my-pair-test/06 (1 2))
'(((1 2))))

Not quite sure why these parens are missing, or why they even need to be there...

Error reporting when running from file

When throwError is called, the error is not printed if running from the cmd line, only if running from the shell. in both cases, the user should see the error msg, to make debugging easier.

Implement (rationalize)

From the spec:

library procedure: (rationalize x y)

Rationalize returns the simplest rational number differing from x by no more than y. A rational number r1 is simpler than another rational number r2 if r1 = p1/q1 and r2 = p2/q2 (in lowest terms) and |p1| < |p2| and |q1| < |q2|. Thus 3/5 is simpler than 4/7. Although not all rationals are comparable in this ordering (consider 2/7 and 3/5) any interval contains a rational number that is simpler than every other rational number in that interval (the simpler 2/5 lies between 2/7 and 3/5). Note that 0 = 0/1 is the simplest rational of all.

(rationalize
  (inexact->exact .3) 1/10)          ===> 1/3    ; exact
(rationalize .3 1/10)                ===> #i1/3  ; inexact

No hygienic macros.

You don't have hygienic macros. For example using,

(define-syntax orr (syntax-rules () ((orelse <expr1> <expr2>) (let ((temp <expr1>)) (if temp temp <expr2>)))))

I'm getting

(let ((temp 4)) (orr #f temp)) => #f instead of 4

The other side of hygiene is much harder to get right:

(let ((if +)) (orr 1 1)) => 1

seems that it's working, which surprised me after failing the easy side... But apparently, you don't even have lexical scope implemented properly:

(let ((if +)) (if (orr 1 1) 10 100)) => 10 instead of 111

or more directly:

(let ((if +)) (if 1 2 3)) => 2 instead of 6

The quick fix that every toy scheme does is dropping claims that it supports hygiene. In this case, you have even bigger problems...

Improved handling of comments in source files

This part of the interpreter could be improved. Issues include:

  • huski crashes if the first line of a scheme file is blank
  • Correct parsing of comments, including allowing them in the middle of a form (eg: (cond))

Might consider implementing a tokenizer that takes care of these issues prior to loading source code.

Order of arguments in function passed to (fold)

From Rotsor's email:

Hello Justin!

I was porting one Scheme script from Guile to Husk and noticed one problem -- (fold (lambda (x y) x) 8 (list 1 2 3)) in Guile yields 3, the same expression in Husk yields 8. The reason for that seems to be the order of arguments for the lambda-expression. In Husk it's flipped relative to the Guile's.

I believe there is no fold in R5RS, it is introduced by SRFI 1. So, my question is -- what are your thoughts on this? What, if anything, are the additional functions in standard library supposed to be compatible with? Should I just rewrite the offending functions?

Thank you!
Arseniy.

Implement dynamic-wind

Now that continuations are implemented, the dynamic-wind function should be implemented as well.

In addition, other continuation-related functions need to be implemented as well: - `(values obj ...)` - `(call-with-values producer consumer)`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.