Git Product home page Git Product logo

little-scheme's Introduction

Little Scheme

A little scheme implementation

Installation

To install the interpreter you can:

git clone https://github.com/dannypsnl/little-scheme.git
cd little-scheme
runhaskell Setup.hs configure --ghc
runhaskell Setup.hs build
runhaskell Setup.hs install

To complete remove all stuffs from Little Scheme you can:

little-scheme cleanup

Using

little-scheme supports two ways to evalute scheme program right now.

  • little-scheme examples/hello.scm would evalute examples/hello.scm.
  • little-scheme would create a REPL.

Contributing

  1. Install direnv
  2. (If Zsh) Edit your ~/.zshrc and add following code at the end
    eval "$(direnv hook zsh)"
  3. (Not Zsh) https://github.com/direnv/direnv/blob/master/docs/hook.md
  4. cabal build and others commands are working now.
Reference

little-scheme's People

Contributors

dannypsnl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

hermetique

little-scheme's Issues

introduce `use-modules`

Basically, use-modules is for any bigger program than examples/hello.scm or examples/filter.scm. When we create a big module, load will import too many stuff that we can't organize. With use-modules, we write:

(use-modules (stdlib list))

(list 1 2 3)

We only import list into the current scope, which is helpful for the real world project.

Conditionals

  • if
  • cond
    form: cond clause clause ...
    clause: (predicate expression …) or (else expression expression …)
    (cond ((> 3 2) 'greater)
      ((< 3 2) 'less))                  ⇒  greater
    
    (cond ((> 3 3) 'greater)
      ((< 3 3) 'less)
      (#t 'equal))                    ⇒  equal
  • case
    (case (* 2 3)
       ((2 3 5 7) 'prime)
          ((1 4 6 8 9) 'composite))            ⇒  composite
    
    (case (car '(c d))
       ((a) 'a)
       ((b) 'b))                            ⇒  unspecified
    
    (case (car '(c d))
       ((a e i o u) 'vowel)
       ((w y) 'semivowel)
       (else 'consonant))                   ⇒  consonant

ref: https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Conditionals.html

Load from default path

For now, we can write (load "stdlib.scm") is because we work under this project root. However, users won't always work like that and it's very inconvenience.

To avoid this situation, we have to provide a default place to install these standard libraries.

BUG: fix lazy initialize environment

The current problem is the lib/ is rely on the executing file path when you run little-scheme out of the source directory without a prepared library then the init process failed.

To solve this we have to embed the lib/ into binary.

feature: Lexical Binding

  • special form: let ((variable init) …) expression expression …
    (let ((x 2) (y 3))
      (* x y))                              ⇒  6
    
    (let ((x 2) (y 3))
      (let ((foo (lambda (z) (+ x y z)))
            (x 7))
        (foo 4)))                           ⇒  9
  • special form: let* ((variable init) …) expression expression …
    (let ((x 2) (y 3))
      (let* ((x 7)
             (z (+ x y)))
        (* z x)))                           ⇒  70
  • special form: letrec ((variable init) …) expression expression …
    (letrec ((even?
              (lambda (n)
                (if (zero? n)
                    #t
                    (odd? (- n 1)))))
             (odd?
              (lambda (n)
                (if (zero? n)
                    #f
                    (even? (- n 1))))))
      (even? 88))                           ⇒  #t

ref

command option

Now every command in little scheme has no options, however, it would be a thing in the near future. We can cut the argument list by break.

Add transform layer

Right now eval function takes too many responsibilities. That make add function such as call/cc
or compiling became quite hard. To solve this, we would add a transform layer to ensure the special form such as let let* letrec can be converted to lambda first.

Then do calculus-conversion and CPS-conversion would be easier.

TODO(order is not important):

Improve error message from apply

When we have the following form, at before we would get little-scheme: src/Scheme/Interpreter.hs:(179,1)-(190,30): Non-exhaustive patterns in function apply because the apply function do not cover all cases, to fix that, we should cover and report we are calling some not a function.

(0 1)
;;; => Applying a not function value: 0

BUG: fix identifier parser

Reproduce:

  1. little-scheme
  2. run #a
  3. got: Can not found variable: #a

This is because I mixing syntax of #f and #t with the normal identifier, but they are different in the scheme definition. Should separate their parser.

fix clause form

When implementing cond and case, I didn't correctly implement clause.

clause should like let:

(let ((x 2))
  1
  x)

can have multiple expressions as the body!

But for now

(cond (#t 1 2))

would break the interpreter.

Try stack

just a try, if stack is better than swap to stack.

little-scheme stop maintaining

Well, just like elz, and anyway this is a toy project. Rather than improving this, make a new one actually faster from my perspective XD.

Proper bug: An unused variable

When compiling with wall flag, GHC points out in Interpreter.hs has a Defined but not used variable, and it evaluates a key object in case form for comparing it with objects in case. It seems like a bug.

src/Scheme/Interpreter.hs:69:7: warning: [-Wunused-matches]
    Defined but not used: ‘result’
   |
69 |       result <- eval env key
   |

allow use `[` `]` work as `(` `)`

For a lexical binding program such as:

(let ((x 1) (y 2))
  (+ x y))

Find a binding is a little bit hard.

If we allow [ ]:

(let ([x 1] [y 2])
  (+ x y))

We can find the binding by [ ] without thinking about the parenthesis.

Switch to bazel

Found bazel is better than CMake, at least more readable.

lazy preparing environment

Right now little scheme requires little-scheme init to explicit prepare libraries. It should automatically prepare environment when do not have one.

Would need:

  • embedded lib/* into binary so that we can remove code base and still safely
  • update Main function to do lazy preparing

structure

An example take from racket reference:

(struct point (x y) #:inspector #f)
(point 3 5)
(struct celsius (temp)
  #:guard (λ (temp name)
      (unless (and (real? temp) (>= temp -273.15))
         (error "not a valid temperature"))
      temp))
(celsius -275)
;;; result: not a valid temperature

But I'm not sure we need such a complex definition for struct.

Reference

https://docs.racket-lang.org/reference/define-struct.html

report location of error

For example, the following code leads Can not found variable: y:

((lambda (x) y) 1)

However, in a bigger program, we can't get location would cause debugging hard.

To avoid this we have to record the location of expression, in the case is (0, 14), create an error: file.scm (0, 14): Can not found variable: y

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.