manifesto and half-assed interoperability

This commit is contained in:
Brian Picciano 2014-10-06 12:34:04 -04:00
parent d4b92d96ad
commit 33bee1efaf
3 changed files with 215 additions and 136 deletions

151
README.md
View File

@ -1,147 +1,26 @@
# Ginger # Ginger
A lisp-like language built on the go programming language. The ideas are still a A lisp-like language built on the go programming language. The ideas are still a
work-in-progress, and this repo is where I'm jotting down my notes. work-in-progress, and this repo is where I'm jotting down my notes:
# Goals # Language manifesto
I have some immediate goals I'm trying to achieve with this syntax: * Anything written in go should be writeable in ginger in as many lines or
fewer.
* Everything is strings (except numbers, functions, and data structures). There * When deciding whether to be more go-like or more like an existing lisp
is no symbol type, atom type, keyword type, etc... they're all just strings. language, err on being go-like.
* There is no `defmacro`. Macro creation and usage is simply an inherent feature * The fewer built-in functions, the better. The standard library should be
of the language syntax. easily discoverable and always importable so helper functions can be made
available.
# Walkthrough * When choosing between adding a syntax rule or a datatype and not adding a
feature, err on not adding the feature.
This is a number which evalutates to 5: * It is not a goal to make ginger code be usable from go code.
``` * Naming should use words instead of symbols, except when those symbols are
5 existing go operators.
```
This is a string, it can contain anything: * Overloading function should be used as little as possible.
```
"! I'm the king of the world !"
```
This is a list. It evaluates to a linked-list of four strings:
```
("a" "b" "c" "d")
```
This is a vector of those same elements. It's like a list, but has some slightly
different properties. We'll mostly be using lists:
```
["a" "b" "c" "d"]
```
This is a string
```
"+"
```
`:` is the evaluator. A string beginning with `:` is evaluated to whatever it
references. This evaluates to a function which adds its arguments:
```
":+"
```
This evaluates to list whose elements are a function and two numbers:
```
(":+" 1 2)
```
A list whose first element is a `:` calls the second element as a function with
the rest of the elements as arguments. This evaluates to the number 5:
```
(":" ":+" 1 2)
```
A bare string (lacking in `"`) is automatically prefixed with a `:`, if it
doesn't already have one. So `":+"`, `:+`, and `+`, are equivalent. `":"` and
`:` are also equivalent. This is equivalent to the previous example:
```
(: + 1 2)
```
The `fn` function can be used to define a new function. Note the `.` instead of
`:`. We'll cover that in a bit. This evaluates to an anonymous function which
adds one to its argument and returns it:
```
(. fn [x]
(: + x 1))
```
The `def` function can be used to bind some value to a new variable. This
defines a variable `foo` which evaluates to the string `"bar"`:
```
(. def foo "bar")
```
This defines a variable `incr` which evaluates to a function which adds one to
its argument:
```
(. def incr
(. fn [x]
(: + x 1)))
```
This uses `defn` as a shortcut for the above:
```
(. defn incr [x]
(: + x 1))
```
There are also maps. A map's keys can be any value(?). A map's values can be any
value. This evaluates to a map with 2 key/val pairs:
```
{ "foo" foo
"bar" (: incr 4) }
```
`.` is the half-evaluator. It only works on lists, and runs the function given
in the first argument with the unevaluated arguments (even if they have `:`).
You can generate new code to run on the fly (macros) using the normal `fn`. This
evaluates to a `let`-like function, except it forces you to use the capitalized
variable names in the body (utterly useless):
```
#
# eval evaluates a given value (either a string or list). It has been
# implicitely called on all examples so far.
#
# elem-map maps over every element in a list, embedded or otherwise
#
# capitalize looks for the first letter in a string and capitalizes it
#
(. defn caplet [mapping body...]
(. eval
(. let
(: elem-map
(. fn [x]
(. if (: mapping (: slice x 1))
(: capitalize x)
x))
mapping)
body...)))
#Usage
(. caplet [foo "this is foo"
dog "this is dog"]
(: println Foo)
(: println Dog))
```

53
go-interop.md Normal file
View File

@ -0,0 +1,53 @@
# Go interop
Ginger translates down to go code, and many of its conventions and rules follow
from go's conventions and rules. In most cases these decisions were made to help
with interoperability with existing go code.
## Referencing go package variables/functions
See the package doc for more on this
## Types
Go types and ginger types share a lot of overlap:
* Ginger strings are of go's `string` type
* Ginger integers are of go's `int` type
* Ginger floats are of go's `float32` type
* Ginger characters are of go's `rune` type
* Ginger errors are of go's `error` type
## Casting
Each go type has a corresponding ginger casting function:
```
(: int64 5)
(: float64 5.5)
(: rune 'a')
```
## go-drop
the `go-drop` form can be used for furthur interoperability. The rationale
behind `go-drop` is that there are simply too many cases to be able to create
enough individual functions, or a few generic functions, that would cover all
cases. Instead we use a single function, `go-drop`, which lets us drop down into
go code and interact with it directly. There are a number of pre-made functions
which implement commonly needed behaviors, such as `StringSlice` and
`ByteSlice`, which cast from either go or ginger types into `[]string` and
`[]byte`, respectively.
```
(. go-drop
"func StringSlice(v ginger.Elem) []string {
ret := []string{}
// do some stuff
return ret
}")
```

147
syntax.md Normal file
View File

@ -0,0 +1,147 @@
# Syntax
This document describes the ginger syntax and data-structures, and how they are
evaluated.
# Goals
I have some immediate goals I'm trying to achieve with this syntax:
* Everything is strings (except numbers, functions, and data structures). There
is no symbol type, atom type, keyword type, etc... they're all just strings.
* There is no `defmacro`. Macro creation and usage is simply an inherent feature
of the language syntax.
# Walkthrough
This is a number which evalutates to 5:
```
5
```
This is a string, it can contain anything:
```
"! I'm the king of the world !"
```
This is a list. It evaluates to a linked-list of four strings:
```
("a" "b" "c" "d")
```
This is a vector of those same elements. It's like a list, but has some slightly
different properties. We'll mostly be using lists:
```
["a" "b" "c" "d"]
```
This is a string
```
"+"
```
`:` is the evaluator. A string beginning with `:` is evaluated to whatever it
references. This evaluates to a function which adds its arguments:
```
":+"
```
This evaluates to list whose elements are a function and two numbers:
```
(":+" 1 2)
```
A list whose first element is a `:` calls the second element as a function with
the rest of the elements as arguments. This evaluates to the number 5:
```
(":" ":+" 1 2)
```
A bare string (lacking in `"`) is automatically prefixed with a `:`, if it
doesn't already have one. So `":+"`, `:+`, and `+`, are equivalent. `":"` and
`:` are also equivalent. This is equivalent to the previous example:
```
(: + 1 2)
```
The `fn` function can be used to define a new function. Note the `.` instead of
`:`. We'll cover that in a bit. This evaluates to an anonymous function which
adds one to its argument and returns it:
```
(. fn [x]
(: + x 1))
```
The `def` function can be used to bind some value to a new variable. This
defines a variable `foo` which evaluates to the string `"bar"`:
```
(. def foo "bar")
```
This defines a variable `incr` which evaluates to a function which adds one to
its argument:
```
(. def incr
(. fn [x]
(: + x 1)))
```
This uses `defn` as a shortcut for the above:
```
(. defn incr [x]
(: + x 1))
```
There are also maps. A map's keys can be any value(?). A map's values can be any
value. This evaluates to a map with 2 key/val pairs:
```
{ "foo" foo
"bar" (: incr 4) }
```
`.` is the half-evaluator. It only works on lists, and runs the function given
in the first argument with the unevaluated arguments (even if they have `:`).
You can generate new code to run on the fly (macros) using the normal `fn`. This
evaluates to a `let`-like function, except it forces you to use the capitalized
variable names in the body (utterly useless):
```
#
# eval evaluates a given value (either a string or list). It has been
# implicitely called on all examples so far.
#
# elem-map maps over every element in a list, embedded or otherwise
#
# capitalize looks for the first letter in a string and capitalizes it
#
(. defn caplet [mapping body...]
(. eval
(. let
(: elem-map
(. fn [x]
(. if (: mapping (: slice x 1))
(: capitalize x)
x))
mapping)
body...)))
#Usage
(. caplet [foo "this is foo"
dog "this is dog"]
(: println Foo)
(: println Dog))
```