From f30332a982daccc65f0009d32e9f7e5c27bd2a06 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Mon, 13 Jan 2020 10:18:36 +0000 Subject: [PATCH] Serene simple version post has been updated --- _posts/2020-01-03-serene-simple-version.md | 79 +++++++++++----------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/_posts/2020-01-03-serene-simple-version.md b/_posts/2020-01-03-serene-simple-version.md index 33c5738..9731f28 100644 --- a/_posts/2020-01-03-serene-simple-version.md +++ b/_posts/2020-01-03-serene-simple-version.md @@ -6,30 +6,32 @@ categories: Programming tags: Serene language theme: dark --- -As you might already know I'm working on [my own programming language ](programming/my-new-programming-language/) +As you might already know I'm working on [my own programming language ](/programming/my-new-programming-language/) for a while now. I'm still on early stages and I'm working on [choosing the right platform](/programming/choosing-the-target-platform/) -for [#Serence](https://social.lxsameer.com/tags/Serene) and trying +for [#Serene](https://social.lxsameer.com/tags/Serene) and trying to spend time on doing enough research and make decision based on facts, scientific papers and collected data from experiments rather than rushing into things and end up with a mess. I believe those languages that take their time and move slowly but with great research, plan and design are more successful in the long term (Thanks to **Pouya** for pointing it out). Take **Clojure** -as an example. They are taking their time experimenting and validating +as an example. They are taking their time, experimenting and validating their hypothesis. As a result, Clojure is a well designed, stable -and highly backward compatible language with amazing productivity +and highly backward compatible language with amazing and productive pace. However, some other languages like Python are extremely popular and consequently has more contributors. Dealing with all those contributors caused Python to move faster than it should and they ended up with some bad choices and horrible designs that -fixing them requires an humongous effort. Little by little, it becomes +fixing them requires an humongous effort. Gradually, it becomes harder and harder to fix those and move away from them. GIL is a good example, instead of fixing the issue and removing the GIL, they are introducing +(at the of writing this article they added some basic support to latest +python release but far from what they want) [something else](https://lwn.net/Articles/754162/) to fix the original problem but it might become a pain point itself. In order to avoid these kind of problem as much as possible I'm trying to take my time and do as -many as experiments that I need. +many as experiments as I need. As I mentioned [earlier](/programming/choosing-the-target-platform/) I think **GraalVM** and **Truffle** is the right answer for @@ -40,23 +42,23 @@ I'll update the experiment files accordingly at the [experiment reports](https://gitlab.com/serene-lang/experiment-reports/tree/master/001) repository. -I spend several days and implemented the pure java version. There repository +I spent several days and implementing the pure java version. The repository of the simple version is available in the [gitlab repo](https://gitlab.com/serene-lang/simple-version). -This version is a dumb but good enough lisp that I didn't paid too much attention -to the details and created a very simple lisp which follows the specification below. +This is a dummy version, but good enough lisp that I didn't paid too much attention +to the details and just created a very simple lisp with the following specification. -> Node: In this post where ever I use the name **Serene** for the implementation, +> Note: In this post whereever I use the name **Serene** for the implementation, > I'm referring to the simple version. ## Data structures -Since I tried to avoid unnecessary work I didn't do much and implemented -only one collection type which is the most important and essential data -structure of Lisp, the mighty List. While my final goal is to have functional +Since I tried to avoid unnecessary work, I didn't do much and implemented +just one collection type which is the most important and essential data +structure in any Lisp, the mighty List. While my final goal is to have functional data structures, this List is not a functional one and is a simple linked list. You can find the implementation under `serene.simple.ListNode`. -For the number types I just added the support for `Long` and `Double` numbers -via `serene.simple.SNumber` class which act as a dispatcher between two inner +For the number types I just added support for `Long` and `Double` +via `serene.simple.SNumber` class which acts as a dispatcher between two inner classes. For Strings, boolean types and `nil`, I just used the equivalent Java data @@ -64,34 +66,34 @@ structures directly. ## Reader/Parser Instead of using a parser generator or a sophisticated parser, I just created -a simple read ahead position based parser that reads two chars and call the +a simple read ahead of position based parser that reads two chars and calls the appropriate method to create the corresponding `Node`. the `serene.simple.Node` is an abstract class that has just one important method, `eval`. The whole purpose of the reader is to parse the code and create an AST like data structure which each node extends the `Node` class (I should've create the interface for it but too lazy to change it now). The `eval` method of `ListNode` is a bit special. It calls the `eval` method on all the elements on the list -and the call the first element as a function and pass the rest of elements +and then calls the first element as a function and pass the rest of the elements as the arguments to that function. First rule of lisp :)) -The `eval` method of `ListNode` contains more details regarding to java +The `eval` method of `ListNode` contains lots more details regarding to java interop as well which I leave it out of this blog post. ## Scope -Scope are simply a mapping between symbol names and values. Serene consists of two -different scopes, both implemented `serene.simple.IScope` and extends +Scopes are simply a mapping between symbol names and values. Serene consists of two +different scopes, both implemented in `serene.simple.IScope` and extend `serene.simple.AScope` abstract class that contains the logic for symbol lookup and insertion. These two classes are `serene.simple.Scope` which is the general scope and it has a parent/child type of relationship with other instances of the same class or `serene.simple.RootScope` that is the top level scope. Beside that, `RootScope` is pre-populated with all -the builtin functions and types. +the built-in functions and types. ## Special forms Serene's [special forms](https://courses.cs.northwestern.edu/325/readings/special-forms.php) are pretty limited. All of them all classes which extend `serene.simple.SpecialForm` abstract class and inherit from `Node` indirectly. The difference between -special form evaluation and function evaluation is that in case of special forms +special form evaluation and function evaluation is that in case of special forms, Serene does not evaluate the arguments and leaves the evaluation to the special form itself. Here is the list of Serene's special forms: @@ -104,12 +106,12 @@ itself. Here is the list of Serene's special forms: ```clojure (def inc (fn (x) (+ 1 x))) ``` -`quote`: Prevent the evaluation of the given argument and return it as it is: +`quote`: Prevents the evaluation of the given argument and return it as it is: ```clojure (quote (1 2 3 4)) ;; => (1 2 3 4) ``` -`if`: Evaluated the body based on the return value of the given predicate. +`if`: Evaluates the body based on the return value of the given predicate. ```clojure (if (= x 1) @@ -117,7 +119,7 @@ itself. Here is the list of Serene's special forms: (...)) ;; if x is not 1 ``` -`let`: Setup a local scope and runs its body using that scope. +`let`: Sets a local scope and runs its body using that scope. ```cl (let ((x 1) @@ -125,7 +127,7 @@ itself. Here is the list of Serene's special forms: (println x y)) ``` -`do`: Simple group several expressions together. +`do`: Simply groups several expressions together. ```clojure (do @@ -156,17 +158,17 @@ important built in functions: `(count coll)`: Returns the number of elements in the given COLL. -`(reverse coll)`: Return a new list which is the reverse of COLL. +`(reverse coll)`: Returns a new list which is the reverse of COLL. `(list 1 2 3..)`: Creates a list from the given arguments. `(first coll)`: Returns the first element of the given COLL. -`(rest coll)`: Return all the elements beside the first of the given COLL. +`(rest coll)`: Returns all the elements beside the first element of the given COLL. -`(doc fn)`: Return the documentation for the given symbol if any. +`(doc fn)`: Returns the documentation for the given symbol if any. -`(reduce f coll initial)`: Reduce the COLL by applying F to its elements with the +`(reduce f coll initial)`: Reduces the COLL by applying F to its elements with the INITIAL as the default value. F takes two arguments 1) the accumulation 2) the element. `(new Class arg1 arg2...)`: Create a new instance of the given CLASS by passing the given @@ -231,7 +233,7 @@ Here is an example program in Serene simple version (`benchmarks/fib.srns` in th ## What is missing ? Since Serene (simple) is an experimental language and I'll abandon it eventually. -I didn't want to go into a rabbit hole and tried to get to the point as soon as possible. +I didn't want to fall into the rabbit hole and just tried to get to the point as soon as possible. So I sacrificed lots of details. Here is a list of the most important missing details: @@ -239,12 +241,13 @@ details: is a massive task and needs tons of work which doesn't make sense for a toy project. * Unified function interface. -* Requiring different namespaces +* Requiring different namespaces. * A sophisticated parser. My Reader implementation is really cheap that suits a toy project. It might worth investigating on different solutions - including using a parser generator or a head of time read implementation. -* Primitive functions in Serene. I implemented lots of primitive functions - in java rather than Serene itself mostly because of two reasons. Lack of + including using a parser generator or ahead of time read implementation. +* Primitive functions in Serene. I used lots of primitive functions + from java rather than implementing them inSerene itself, mostly because + of two reasons. Lack of macros and namespaces. * Decent [functional] data structures. The only data structure I implemented is list. @@ -253,8 +256,8 @@ details: ## Conclusion I'm not going to improve the simple version anymore at this stage. I'm going to run -some benchmarks to measure different aspect of the current implementation and then -I'll move to the **Truffle** version to continue the +some benchmarks and measure different aspects of the current implementation and then +I'll move to the **Truffle** version and continue the [experiment(001)](https://gitlab.com/serene-lang/experiment-reports/tree/master/001). -Please let me know if you have any comment or question on this topic. As always +Please let me know if you have any comments or questions on this topic. As always I'm available throw social media and email.