CSCM (programming language)

CSCM
Paradigm multi-paradigm, concurrent, functional
Designed by Joseph Wayne Norton
Developer Joseph Wayne Norton
First appeared 2013
Stable release
v0.5.4 / 12 May 2014 (2014-05-12)
Typing discipline dynamic, strong
Scope lexical
License MIT License
Filename extensions .scm, .erl
Website the-concurrent-schemer.github.io
Influenced by
Erlang, Common Lisp, MACLISP, Scheme, Elixir, Clojure, Hy
Influenced
Joxa

CSCM (The Concurrent Schemer) is an implementation of the Scheme programming language built on top of the Erlang virtual machine (BEAM). CSCM combines the sequential programming model of Scheme with the concurrent, distributed, and fault-tolerant programming model of Erlang.

By leveraging the Erlang language, CSCM can target a concise, precise specification of the Scheme language. Consequently, by leveraging the Erlang VM, CSCM can target a performant, robust implementation of the Scheme language. The default language is Scheme R7RS and the default virtual machine is Erlang/OTP 17 or higher. Scheme R5RS is available as a Scheme library.

CSCM builds on top of Erlang in order to provide a Scheme syntax for writing distributed, fault-tolerant, soft real-time, non-stop applications. CSCM also extends Erlang to support meta-programming with hygenic macros and an improved developer experience with a feature-rich REPL.[1]

History

Initial release

Joseph Wayne Norton announced the first release of CSCM on GitHub in March 2013. This release of CSCM was very limited: it did not handle recursive letrecs, binarys, receive, or try;.

Motivation

CSCM is aimed as an:

Joseph Wayne Norton has stated that there were a number of reasons why he started the CSCM project:.[2]

Features

Syntax and semantics

Symbolic expressions (S-expressions)

Being a Scheme, CSCM is an expression-oriented language. Unlike non-homoiconic programming languages, Lisps make no or little syntactic distinction between "expressions" and "statements": all code and data are written as expressions. CSCM brought homoiconicity to the Erlang VM.

Lists

The cons function actually accepts any two values, not just a list for the second argument. When the second argument is not empty and not itself produced by cons, the result prints in a special way. The two values joined with cons are printed between parentheses, but with a dot (i.e., a period surrounded by whitespace) in between:

 > (cons 1 2)
 (1 . 2)
 > (cons "banana" "split")
 ("banana" . "split")

Thus, a value produced by cons is not always a list. In general, the result of cons is a pair. The more traditional name for the cons? function is pair?

Operators

The Erlang operators are used in the same way. The expression

 (* (+ 1 2 3 4 5 6) 2)

evaluates to 42. Unlike functions in Erlang, arithmetic operators in scheme are variadic (or n-ary), able to take any number of arguments.

Lambda expressions and function definition

CSCM has lambda, just like scheme. It also, however, has lambda-match to account for Erlang's pattern-matching capabilities in anonymous function calls.

Start up

Start the Erlang shell.

   erl -pa ./deps/parse-tools/ebin -pa ebin
   Save the "hello word" program as an Erlang string.
   Str = "(define hello-world (lambda () (display \"Hello World!\")))".
   Create an empty Scheme environment.
   Env = scmi_env:the_empty().

Create and register a native Erlang function as a simple implementation for the Scheme display library procedure. The Erlang function writes the given arguments to stdout as Erlang terms and simply returns a Scheme #false to the caller.

   False = {boolean,undefined,false}.
   Proc = {nipv, 0, fun(Args) -> io:format("~p~n", [Args]), False end}.
   scmi_env:define_variable('display', Proc, Env).

Parse and evaluate the "hello world" program.

   {ok, Exp} = scmd_parse:string(Str).
   scmi_eval:eval(Exp, Env).

Call the Scheme "hello-world" procedure and show the Scheme return value in the Erlang shell.

   R = scmi_eval:eval(['hello-world'], Env).
   R.

This section does not represent a complete comparison between Erlang and CSCM, but should give a taste.

Pattern matching

Erlang:

      1> {Len,Status,Msg} = {8,ok,"Trillian"}.
      {8,ok,"Trillian"}
      2> Msg.
      "Trillian"

CSCM:

      > (set (tuple len status msg) #(8 ok "Trillian"))
      #(8 ok "Trillian")
      > msg
      "Trillian"

The basic form of pattern matching expression is:

(match exp [pat body] ...)

List comprehensions

Erlang:

      1> [trunc(math:pow(3,X)) || X <- [0,1,2,3]].
      [1,3,9,27]

CSCM:

      > (list-comp
          ((<- x '(0 1 2 3)))
          (trunc (math:pow 3 x)))
      (1 3 9 27)

Or idiomatic functional style:

      > (lists:map
          (lambda (x) (trunc (math:pow 3 x)))
          '(0 1 2 3))
      (1 3 9 27)

Guards

Erlang:

      right_number(X) when X == 42; X == 276709 ->
      true;
      right_number(_) ->
      false.

CSCM:

      (define right-number?
        ((x) (when (orelse (== x 42) (== x 276709)))
          'true)
        ((_) 'false))

cons'ing in function heads

Erlang:

      sum(L) -> sum(L,0).
      sum([], Total) -> Total;
      sum([H|T], Total) -> sum(T, H+Total).

CSCM:

      (defun sum (l) (sum l 0))
      (defun sum
        (('() total) total)
        (((cons h t) total) (sum t (+ h total))))

or using a ``cons`` literal instead of the constructor form:

      (define sum (l) (sum l 0))
      (define sum
        (('() total) total)
        ((`(,h . ,t) total) (sum t (+ h total))))

Matching records in function heads

Erlang:

handle_info(ping, #state {remote_pid = undefined} = State) ->
    gen_server:cast(self(), ping),
    {noreply, State};
handle_info(ping, State) ->
    {noreply, State};

CSCM:

(define handle_info
  (('ping (= (match-state remote-pid 'undefined) state))
    (gen_server:cast (self) 'ping)
    `#(noreply ,state))
  (('ping state)
   `#(noreply ,state)))

Receiving messages

Erlang:

      universal_server() ->
          receive
              {become, Func} ->
                  Func()
          end.

CSCM:

      (define universal-server ()
        (receive
          ((tuple 'become func)
           (funcall func))))

or CSCM:

      (define universal-server ()
        (receive
          (`#(become ,func)
            (funcall func))))

Examples

Erlang interoperability

Calls to Erlang functions take the form (<module>:<function> <arg1> ... <argn>):

(io:format "Hello, World!")

Functional paradigm

Using recursion to define the Ackermann function:

(define ackermann
  ((0 n) (+ n 1))
  ((m 0) (ackermann (- m 1) 1))
  ((m n) (ackermann (- m 1) (ackermann m (- n 1)))))

Composing functions:

(define compose (f g)
  (lambda (x)
   (funcall f
     (funcall g x))))

(define check ()
  (let* ((sin-asin (compose #'sin/1 #'asin/1))
         (expected (sin (asin 0.5)))
         (compose-result (funcall sin-asin 0.5)))
    (io:format "Expected answer: ~p~n" (list expected))
    (io:format "Answer with compose: ~p~n" (list compose-result))))

Concurrency

Message-passing with Erlang's light-weight "processes":

(defmodule messenger-back
 (export (print-result 0) (send-message 2)))

(define print-result ()
  (receive
    ((tuple pid msg)
      (io:format "Received message: '~s'~n" (list msg))
      (io:format "Sending message to process ~p ...~n" (list pid))
      (! pid (tuple msg))
      (print-result))))

(define send-message (calling-pid msg)
  (let ((spawned-pid (spawn 'messenger-back 'print-result ())))
    (! spawned-pid (tuple calling-pid msg))))

Multiple simultaneous HTTP requests:

(defun parse-args (flag)
  "Given one or more command-line arguments, extract the passed values.

References

  1. "The Concurrent Schemer". Joseph Wayne Norton. Retrieved 2016-08-22.
  2. "CSCM". Rahul Thathoo. Retrieved 2015-01-17.

External links


This article is issued from Wikipedia - version of the 12/1/2016. The text is available under the Creative Commons Attribution/Share Alike but additional terms may apply for the media files.