Carp/docs/LanguageGuide.md

241 lines
8.2 KiB
Markdown
Raw Normal View History

2017-06-26 12:45:18 +03:00
## The Language
2017-06-26 16:58:23 +03:00
### Introduction
2017-06-26 16:50:51 +03:00
Carp borrows its looks from Clojure but the runtime semantics are much closer to those of ML or Rust.
Types are inferred but can be annoted for readability using the ```the``` keyword (see below).
2017-06-26 12:45:18 +03:00
2017-06-26 16:58:23 +03:00
Memory management is handled by static analysis, a value is owned by the function where it was created.
When a value is returned or passed to another function the initial function will give up ownership of it
and any subsequent use will lead to a compiler error. To temporarily lend a value to another function
2019-03-07 16:14:43 +03:00
(for example to print it) a reference must be created, using the ```ref``` special form (or the ```&``` reader macro).
2017-06-26 16:58:23 +03:00
2017-10-17 23:48:02 +03:00
To learn more about the details of memory management, check out [Memory.md](https://github.com/carp-lang/Carp/blob/master/docs/Memory.md)
2017-10-17 23:47:21 +03:00
2017-06-26 17:09:12 +03:00
### Comments
```clojure
2017-06-26 17:14:10 +03:00
;; Comments begin with a semicolon and continue until the end of the line.
2017-06-26 17:09:12 +03:00
```
2017-06-26 12:45:18 +03:00
### Data Literals
```clojure
2017-06-26 17:09:12 +03:00
100 ;; Int
2017-12-18 19:27:51 +03:00
1500l ;; Long
2017-06-26 17:09:12 +03:00
3.14f ;; Float
10.0 ;; Double
true ;; Bool
2017-11-28 10:02:11 +03:00
"hello" ;; &String
\#"hello" ;; &Pattern
2017-06-26 17:09:12 +03:00
\e ;; Char
[1 2 3] ;; (Array Int)
2018-08-30 22:21:45 +03:00
{1 1.0 2 2.0} ;; (Map Int Double)
2017-06-26 12:45:18 +03:00
```
2017-06-26 17:12:41 +03:00
### Type Literals
```clojure
2017-06-26 17:13:24 +03:00
t ;; Type variables begin with a lowercase letter
2017-06-26 17:12:41 +03:00
Int
2017-12-18 19:27:51 +03:00
Long
2017-06-26 17:12:41 +03:00
Float
Double
Bool
String
Pattern
2017-06-26 17:12:41 +03:00
Char
(Array t)
2018-08-30 22:21:45 +03:00
(Map <key-type> <value-type>)
2017-06-26 17:12:41 +03:00
(Fn [<arg-type1> <arg-type2> ...] <return-type>) ;; Function type
```
2017-06-26 12:45:18 +03:00
### Dynamic-only Data Literals
Right now the following data types are only available for manipulation in non-compiled code.
```clojure
2017-06-26 12:45:18 +03:00
(1 2 3) ; list
foo ; symbol
```
2017-12-22 17:09:53 +03:00
### Defining things
```clojure
2017-12-22 17:09:53 +03:00
(defn function-name [<arg1> <arg2> ...] <body>) ;; Define a function (will be compiled, can't be called at the REPL)
(definterface interface-name (Fn [<t1> <t2>] <return>)) ;; Define a generic function that can have multiple implementations
(def variable-name value) ;; Define a global variable (only handles primitive constants for the moment)
(defmacro <name> [<arg1> <arg2> ...] <macro-body>) ;; Define a macro, its argument will not be evaluated when called
(defdynamic <name> [<arg1> <arg2> ...] <function-body>) ;; A function that can only be used at the REPL or during compilation
(defmodule <name> <definition1> <definition2> ...) ;; The main way to organize your program into smaller parts
```
2017-06-26 12:45:18 +03:00
### Special Forms
2017-11-28 10:02:11 +03:00
The following forms can be used in Carp source code and will be compiled to C after type checking
2017-12-22 17:09:53 +03:00
and other static analysis. The first three of them are also available in dynamic functions.
2017-06-26 17:17:25 +03:00
```clojure
2017-12-22 17:09:53 +03:00
(let [<var1> <expr1> <var2> <expr2> ...] <body>) ;; Create local bindings
2017-06-26 17:09:12 +03:00
(do <expr1> <expr2> ... <return-expression>) ;; Perform side-effecting functions, then return a value
(if <expression> <true-branch> <false-branch>) ;; Branching
(while <expression> <body>) ;; Loop until expression is false
(ref <expression>) ;; Borrow an owned value
2017-06-26 16:50:51 +03:00
(address <expression>) ;; Takes the memory address of a value, returns a C-style pointer
(set! <variable> <expression>) ;; Mutate a variable
2019-03-07 16:16:31 +03:00
(the <type> <expression>) ;; Explicitly declare the type of an expression
```
Here's an example of how to use the `the` form to make an identity function that only accepts Integers:
```clojure
(defn f [x]
(the Int x))
2017-06-26 12:45:18 +03:00
```
2017-06-26 16:58:23 +03:00
### Reader Macros
```clojure
2017-06-26 17:09:12 +03:00
&x ;; same as (ref x)
@x ;; same as (copy x)
2017-06-26 16:58:23 +03:00
```
### Named Holes
2017-06-26 16:50:51 +03:00
When using a statically typed language like Carp it can sometimes be hard to know what value should
be used at a specific point in your program. In such cases the concept of 'holes' can be useful. Just
add a hole in your source code and reload (":r") to let the Carp compiler figure out what type goes there.
```clojure
(StringCopy.append ?w00t @"!") ;; Will generate a type error telling you that the type of '?w00t' is String
2017-06-26 12:45:18 +03:00
```
2017-12-23 08:38:45 +03:00
### Special forms during evaluation of dynamic code
```clojure
2017-06-26 17:09:12 +03:00
(quote <expression>) ;; Avoid further evaluation of the expression
2017-12-23 08:38:45 +03:00
(and) (or) (not) ;; Logical operators
```
### Dynamic functions
These can only be used at the REPL and during macro evaluation. Here's a subset with some of the most commonly used ones:
```clojure
2017-06-26 17:09:12 +03:00
(car <collection>) ;; Return the first element of a list or array
(cdr <collection>) ;; Return all but the first element of a list or array
(cons <expr> <list>) ;; Add the value of <expr> as the first element the <list>
2017-12-18 19:27:51 +03:00
(cons-last <expr> <list>) ;; Add the value of <expr> as the last element the <list>
2017-06-26 17:09:12 +03:00
(list <expr1> <expr2> ...) ;; Create a list from a series of evaluated expressions
(array <expr1> <expr2> ...) ;; Create an array from a series of evaluated expressions
2017-06-26 14:45:51 +03:00
```
2017-12-22 17:09:53 +03:00
To see all functions available in the `Dynamic` module, enter `(info Dynamic)` at the REPL.
2017-06-26 16:58:23 +03:00
### Modules and Name Lookup
2017-06-26 14:45:51 +03:00
Functions and variables can be stored in modules which are named and can be nested. To use a symbol inside a module
you need to qualify it with the module name, like this: ```Float.cos```.
2017-09-06 15:43:41 +03:00
*Using* a module makes it possible to access its members without qualifying them:
2017-06-26 14:45:51 +03:00
```clojure
2017-09-06 15:43:41 +03:00
(use Float)
2017-06-26 14:45:51 +03:00
(defn f []
(cos 3.2f))
```
2017-09-06 15:43:41 +03:00
If there are several used modules that contain symbols with the same name, the type inferer will try to figure
2017-06-26 14:45:51 +03:00
out which one of the symbols you really mean (based on the types in your code). If it can't, it will display an error.
For example, both the module ```String``` and ```Array``` contain a function named 'length'. In the following code it's
2017-06-26 14:45:51 +03:00
possible to see that it's the array version that is needed, and that one will be called:
```clojure
2017-09-06 15:43:41 +03:00
(use String)
(use Array)
2017-06-26 14:45:51 +03:00
(defn f []
(length [1 2 3 4 5]))
2017-06-26 14:45:51 +03:00
```
In the following example it's not possible to figure out which type is intended:
```clojure
2017-09-06 15:43:41 +03:00
(use String)
(use Array)
2017-06-26 14:45:51 +03:00
(defn f [x]
(length x))
2017-06-26 14:45:51 +03:00
```
Specifying the type solves this error:
```clojure
2017-09-06 15:43:41 +03:00
(use String)
(use Array)
2017-06-26 14:45:51 +03:00
(defn f [x]
(String.length x))
2017-06-26 12:45:18 +03:00
```
### Structs
```clojure
2017-06-26 16:50:51 +03:00
(deftype Vector2 [x Int, y Int])
2017-06-26 12:45:18 +03:00
2017-06-26 16:50:51 +03:00
(let [my-pos (Vector2.init 10 20)]
2017-06-26 12:45:18 +03:00
...)
;; A 'lens' is automatically generated for each member:
2017-06-26 16:50:51 +03:00
(Vector2.x my-pos) ;; => 10
(Vector2.set-x my-pos 30) ;; => (Vector2 30 20)
(Vector2.update-x my-pos inc) ;; => (Vector2 11 20)
2017-06-26 12:45:18 +03:00
```
2017-06-26 16:58:23 +03:00
### C Interop
```clojure
2017-12-18 19:27:51 +03:00
(system-include "math.h") ;; compiles to #include <math.h>
(local-include "math.h") ;; compiles to #include "math.h"
(register blah (Fn [Int Int] String)) ;; Will register the function 'blah' that takes two Int:s and returns a String
2017-06-26 16:50:51 +03:00
(register pi Double) ;; Will register the global variable 'pi' of type Double
(register blah (Fn [Int Int] String) "exit") ;; Will register the function 'blah' but use the name 'exit' in the emitted C code.
(register-type Apple) ;; Register an opaque C type
(register-type Banana [price Double, size Int]) ;; Register an external C-structs, this will generate getters, setters and updaters.
2017-06-26 12:45:18 +03:00
```
### Patterns
Patterns are similar to, but not the same as, Regular Expressions. They were
derived from [Lua](http://lua-users.org/wiki/PatternsTutorial), and are useful
whenever you want to find something within or extract something from strings.
They are simpler than Regular Expressions, as they do not provide alternation.
Nonetheless, they are often very useful and, because they are simpler, also
faster and more predictable.
Here is a little overview of the API:
```clojure
; you can initialize a pattern with a literal or create one from a string
#"[a-z]"
(Pattern.init "[a-z]")
; you can also get a string back from it
(str #"[a-z]")
(prn #"[a-z]")
; you can find things in strings by index
(Pattern.find #"[a-z]" "1234a") ; => 4
(Pattern.find #"[a-z]" "1234") ; => -1
; also multiple things at once!
(Pattern.find-all #"[a-z]" "1234a b") ; => [4 6]
; matches? checks whether a string matches a pattern
(Pattern.matches? #"(\d+) (\d+)" " 12 13") ; => true
; match returns all match groups of the first match
(Pattern.match #"(\d+) (\d+)" " 12 13") ; => ["12" "13"]
; match-str returns the whole string of the first match
(Pattern.match #"(\d+) (\d+)" " 12 13") ; => "12 13"
; global-match gets all match groups of all matches
(Pattern.global-match #"(\d+) (\d+)" " 12 13 14 15") ; => [["12" "13"] ["14" "15"]]
; substitute helps you replace patterns in a string n times
(Pattern.substitute #"sub-me" "sub-me sub-me sub-me" "replaced" 1) ; => "replaced sub-me sub-me"
; if you want to replace every occurrence, use -1
(Pattern.substitute #"sub-me" "sub-me sub-me sub-me" "replaced" -1) ; => "replaced replaced replaced"
```