Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added INSTALL file,

I didn't implement the proper "install", because it's not stable enough to be installed long term on a system.
  • Loading branch information...
commit 7e301de7c3dca8e142fd9133ec70f49a177376c0 1 parent 6c1684a
@pikatchu authored
Showing with 41 additions and 227 deletions.
  1. +21 −0 INSTALL
  2. +2 −0  Makefile
  3. +12 −225 README
  4. +6 −2 configure
View
21 INSTALL
@@ -0,0 +1,21 @@
+DEPENDENCIES:
+
+To compile linearML, you need:
+
+* a unix platform (won't work with windows)
+* a C compiler (only test with gcc)
+* a C++ compiler (only tested with g++)
+* llvm-2.8
+* ocaml-3.11 (or higher)
+* llvm-ocaml bindings (usually installed with llvm-2.8)
+
+
+Instructions install LinearML
+
+step1:
+
+./configure
+
+step2:
+
+make
View
2  Makefile
@@ -5,6 +5,8 @@ default: compiler/limlc
compiler/limlc: Makefile.config
cd compiler && make
+ cd stdlib && make
+ cp compiler/limlc .
stdlib/libliml.lmli: compiler/limlc
@echo "Compiling the standard library"
View
237 README
@@ -1,230 +1,17 @@
-Motivations:
+LinearML (or LiML) is a pogramming language designed to write efficient parallel programs.
+Its main characteristics are:
-LinearML is a language designed to write safe, fast, parallel program.
-It is purely functional, but without a garbage collector.
-Linear types are used to enforce static garbage collection.
+ * Purely functional
+ * Statically typed
+ * Strict evaluation order
-The priorities of LiML are (in order):
- 1) Safety
- I won't include anything that could make programs crash at runtime
- (including division by zero !). A LiML program can only crash for 3 reasons:
- a) You blew up the stack
- b) You blew up the ram
- c) you used an external C function
+In LiML, the default is, every value has a linear type, this implies:
- 2) Speed
- Speed has been one of my main concerns while designing the language.
- I got rid of "convenient" language features whenever they made me loose
- speed.
- Why is speed so important ?
- Because if a sequential C program beats a parallel LiML program ...
- There is no point in using LiML.
+ * Thread-safe copy-less message-passing between threads
+ * Thread-safe IOs
+ * In-place updates for the vast majority of operations (better cache hits)
+ * Statically enforced memory management.
+ In other words, there is no garbage collector, the memory usage is safe, it's garanteed statically !
- 3) Simplicity
- The language is small, it will stay small. This is an anti-C++ approach !
- You should be able to get familiar with all the constructions of the language
- rapidely.
- 4) Full Compatibility with C
- LinearML is designed to be fully compatible with C, one can call LiML functions
- from a C program and vice-versa (without any wrapper!).
-
-Getting Started)
-
-You can find functional examples in test/
-Because for now, the seperate compilation is broken, you need to include the entire standard library every time.
-to compile an example (in the test directory):
-
-../limlc ../stdlib/*.ml my_test.ml
-
-All the ".bc" files (llvm bytecode), have been created.
-To compile them use llc (produces ".s" assembly files).
-
-For now the main has to be written in C (I left an example in test/my_main.c).
-The final step consists in linking all the files together, for example:
-
-gcc ../stdlib/*.o my_file.s my_main.c -o my_exec_name
-
-I) About the structure of a program:
-
- A program is always made of a list of module (there is no toplevel declarations):
-
- //////////////////////////////////
- module MyModule = struct
-
- .... a bunch of function and type definition
- .... NO GLOBALS
- .... NO SUB-MODULE
-
- end
-
- module MyNextModule = struct ... end
- //////////////////////////////////
-
- There is only one level of modules. You cannot open their namespace (like in ocaml),
- this is a delibarate choice, one should use aliasing instead. If a module name is too long,
- use
- module A = MySpecialArray
- Past this point you will be able to use A.f instead of MySpecialArrayModule.f.
-
-II) About the types:
-
- The type representation is designed to be fully compatible with C.
- I still need to add the primitive C types though, I use int32 instead of int,
- assuming the architecture is going to be 32 bits ... This is bad.
-
- Functions)
-
- The main problem comes from the x86 calling convention, llvm doesn't optimize every
- tail call for this convention. Plus, the x86 calling convention is not very fast,
- because LiML is purely functional and every loop has to be encoded with recursive calls,
- I needed a better (more flexible) calling convention.
-
- The compromise I found is to use 2 different types.
- A function of type #-> uses the C calling convention, a function of type -> uses
- the "fast" calling convention.
-
- Tuples)
-
- You will soon realize that a tuple is not a "real" value. That is, you cannot
- define a list of couples for example, you will have to define a record for that.
- This is because, I absolutely didn't want tuple creation to allocate.
- Allocation is no way near as fast as ocaml's minor heap, because we use malloc/free.
- The overhead would have been far too high.
- So the good news is, tuples don't allocate, the bad news is, 'a is incompatible with
- 'a * 'a.
-
- Option)
-
- The option type is one of the very few built-in type.
- It's semantics is very strange ... but for good reasons.
- The strangeness comes from the fact that ((Some None) = None) !
- Therefore the expression:
- match x_opt with None -> do_this | Some x -> do_that
- Compiles to:
- if x_opt == NULL then do_this else do_that
-
- This is to speed-up array access.
- In LiML, when you want to retrieve an element of an array, you swap the element
- with NULL.
- let t, x = Array.get t 32 in
- (* From now on the 32nd element of t = NULL *)
-
- Because of that, every access returns an 'a option (instead of an 'a).
- We would loose linearity without that.
- This implies, that we need to create an option type every time we want to insert
- an element in an array and we don't want to allocate to do that!
-
- If you dislike this behaviour you can always define your own option type.
-
- Besides, the remarks on array access don't apply to arrays containing primitive
- values (they work exatly like in C).
-
- Polymorphic Types)
-
- A polymorphic type in LiML, doens't mean any type, it means any pointer.
- This is for good compatibility with C.
- let's say you define the identity function.
-
- val f: 'a -> 'a
- let f x = x
-
- You will be able to apply this function to a record, an algebric data type,
- but not to a float or an int.
- You will have to either box the integer or specialize f to f_int to do that.
-
- Records)
-
- A record works a bit like a shelf, take out what you need, work with it, put
- it back !!
-
- Let's take an example
- ////////////////////////////////////////////////
-
- type ('a, 'b) couple = { fst: 'a; snd: 'b }
-
- val do_work: ('a, 'a) couple -> ('a, 'a) couple
- let do_work cpl =
-
- (* First we take out the values we need *)
-
- let { cpl; fst = fst ; snd = snd } = cpl in
-
- (* Alternative syntax: let { cpl; ~fst; ~snd} = cpl in *)
- (* From now on, you cannot access the fields fst and snd anymore *)
- (* If you try to do so, the compiler complains ! *)
-
- let x, y = do_some_work fst snd in
-
- (* We now have 2 options *)
- (* Option 1: we create a new record and free the old one *)
- free cpl ;
- { fst = x ; snd = y }
-
- (* Option2: we modify cpl *)
- { cpl with fst = x ; snd = y }
- //////////////////////////////////////////////
-
- The type system enforcing that everything you do with records is safe
- is called RecordCheck (in recordCheck.ml).
-
-
-III) About linear types
-
- Basic Linear Types)
-
- In LiML, the default is, everything has a linear type, except for primitive types and functions.
- If you try to use a value more than once, the compiler complains.
- If you don't use a value, the compiler complains.
-
- Algebric data types)
-
- Algebric data types are destroyed while they are pattern-matched.
- let x = A 32 in
- match x with
- | A v ->
- (* Passed this point x is dead *)
- A (v + 1)
- | B v -> ...
-
- If one destroys an object of type A, and then redefines one straight away,
- The allocation is optimized (done in-place).
- In the example above, the first branch modifies A in-place.
-
- Branches)
-
- Whenever you use an object you must use it in all the branches of a conditional expression.
- However, there is one case where this constraint is relaxed, when using the "as" pattern.
-
- match x with (A x y) as z ->
- if ...
- then f x y (* This is OK because we use both x and y, but not z *)
- else g z (* This is OK because we use z, but neither x nor y *)
-
- Observers)
-
- It is possible to use an object multiple times by using observers:
- (obs x) means, I am not really using x, I am just observing it.
- Some operation on observed values are not allowed:
- *) Taking an observed value and embedding it into another value.
- *) Returning an observed value
- *) aliasing an observed value
-
- Observing functions are useful to traverse data structures without destroying them.
- classical examples would be: copy, compare, hash, List.length etc ...
-
-IV) About the runtime
-
- There is no runtime :-) !
-
-
-TODO List:
-
-Unfortunately, LiML is not finished :-(
-Here is the list of things I still have to do:
-
-1) add string type
-2) add C primitive types char short int long etc ...
-3) add closures
-4) Finish the standard library
-5) Better integration of C functions (parsing C headers ?)
+To compile LiML, follow the instructions in INSTALL
View
8 configure
@@ -325,7 +325,8 @@ fi
fi
if test -z "$libdir"; then
- stdlibdir="/usr/lib/liml"
+ libdir="$PWD/stdlib"
+ # will do for now
fi
config="Makefile.config"
@@ -382,4 +383,7 @@ echo "let ar = \"$ar\"" >> "$config_ml"
echo ""
echo -e "Generated\t: $config"
echo -e "Generated\t: $config_ml"
-echo -e "Generated\t: $config_h"
+echo -e "Generated\t: $config_h"
+
+echo ""
+echo "You can now start compiling LinearML"
Please sign in to comment.
Something went wrong with that request. Please try again.