aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: c47c7efc1521b6caa316798fc7fe114af51cb847 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
## What is Lux?

Lux is a new programming language in the making.
It's meant to be a functional, statically-typed Lisp that will run on several platforms, such as the Java Virtual Machine and JavaScript interpreters.

### What's the current version?

v0.1

### How far ahead is the project?

The Java-bytecode compiler is close to completion.

Some features are missing and the compiler is not as fast as I would like.

However, some small programs can be written to try out Lux and get a feeling for the language.

### How can I use it?

Download the 0.1 compiler from here: https://github.com/LuxLang/lux/raw/master/lux-jvm-0.1.0-standalone.jar

Right now, the current version of Lux (0.1) is mostly to play around with the language, so it's a bit limited on what you can do.
Once you download the compiler, you'll want to create a directory named "source" in the same directory where the compiler is located.

"source" must contain 2 files.
One will be the Lux prelude (lux.lux), the other will be program.lux
You can write anything you want inside program.lux to play around with the language.

##### Note: You can download the lux.lux & program.lux files in the source/ directory in this repo to get started.

To run the compiler, open your terminal and write this:

	java -jar lux-jvm-0.1.0-standalone.jar

This will generate a directory named "output" and put all the .class files there.
Then, you can package the program and run it using this:

	cd output && jar cvf program.jar * && java -cp "program.jar" program && cd ..

### What's the license?

Eclipse Public License v1.0

## What's interesting about the language?

### Inspirations

The language is mostly inspired by the following 3 languages:

* Haskell (functional programming)
* Clojure (syntax, overall look & feel)
* ML (module system)

The compiler is even implemented in Clojure.

### Types

They are implemented as plain-old data-structures whose expressions get eval'ed by the compiler and integrated into the type-checker.
That means it's actually possible to generate types via functions.
However, most of the types in the prelude are generated via several macros that provide a more pleasant syntax to types.

If you wonder what types look like without makeup, feel free to read the first few hundred lines of lux.lux.

### Module system

The module system is heavily inspired by ML, and both signatures & structures are suported.

The main difference between Lux and ML is that ML separates signaturs & structures from the rest of the language, whereas Lux implements them on-top of the base language.

How?
By implementing signatures as record-types and structures as actual records.

##### But, why not just use type-classes?

Haskell's type-class system forces the user to only specify 1 instance for any given type-class and it's argument.
This means that if there are more than 1 possible valid instances (as is the case for Monoid of Int), you have to resort to newtype hacks to be able to provide alternative implementations.

By using a system like ML's, that problem is averted.
Also, by hosting the module system on top of records, which are regular values, you get the further benefit that structures can be parameterized at runtime just like any other data-structures.
You can also write functions that take and return structures (as Functors do in ML) and you can generate structures on the fly.

### Functional programming

While the means to do Java-interop will be provided (and there are already a few ways to do it that you can look-up inside lux.lux), Lux is commited to functional programming.

Functions are curried and partial application is as simple as just applying a function to less arguments than it needs (as in Haskell).

e.g.

	(let [inc (int:+ 1)]
	  (map inc (list 1 2 3 4 5)))

### Code portability

Many languages nowadays support compilation to multiple platforms (e.g. Haskell, Scala, Clojure).
However, sharing code between platforms can be a pain in the neck due to the following reasons:

* differences in features between platforms
* the languages weren't originally designed with the goal of running both native/JVM and in JavaScript

Lux is being designed from the ground up to target multiple platforms and achieve maximum reusability of code with minimum hassle.

The mechanism hasn't been added yet to the language (mainly because there's only 1 compiler at the moment), but it will come pretty soon in one of the upcoming releases.

### Macros

Unlike in most other lisps, Lux macros are monadic.
The **(Lux a)** type is the one responsibly for the magic by treading **CompilerState** instances through macros.
Macros must have the **Macro** and then be declared as macros.

However, just using the **defmacro** macro will take care of it for you.

However, in an upcoming release you'll get another macro for defining macros.
It will be named **defsyntax** and will use monadic parsing of AST tokens to parse the syntax.

If you want to see how macros are implemented, you can take a look at *lux.lux*.

### Custom pattern-matching

##### Wait... wut?

Custom pattern-matching basically means that you can use macros to provide custom syntax & features on top of the pattern-matching macro (case).

For instance, the **list** and **list&** macros are used to build lists.
But you can also use them to destructure them inside pattern-matching:

	(case (: (List Int) (list 1 2 3))
	  (#Cons [x (#Cons [y (#Cons [z #Nil])])])
	  (#Some ($ int:* x y z))

	  _
	  #None)

	(case (: (List Int) (list 1 2 3))
	  (\ (list 1 2 3))
	  (#Some ($ int:* x y z))

	  _
	  #None)

There is also the special **\or** macro, which instroduces *or patterns*

	(deftype Weekday
	  (| #Monday
		 #Tuesday
		 #Wednesday
		 #Thursday
		 #Friday
		 #Saturday
		 #Sunday))

	(def (weekend? day)
	  (-> Weekday Bool)
	  (case day
		(\or #Saturday #Sunday)
		true

		_
		false))

##### Please note: \ and \or are just macros like and other and anyone can implement them.

I'll be adding more useful pattern-matching macros in upcoming releases of the language.

If you want to see how they work, just check out their implementation inside lux.lux

### Is there a community for this?

Lux was just born today.

Come join the budding community by joining the discussion group at: https://groups.google.com/forum/#!forum/lux-programming-language

If you want to communicate with me directly, just email me at luxlisp@gmail.com

### How can I edit Lux code?

Check out the Emacs plugin for it: https://github.com/LuxLang/lux-mode

## What's available?

### Base syntax

Comments

	## This is a single-line comment
	## Multi-line comments are comming soon

Bool (implemented as java.lang.Boolean)

	true
	false

Int (implemented as java.lang.Long)

	1
	20
	12345

Real (implemented as java.lang.Double)

	1.23
	0.5

Char (implemented as java.lang.Character)

	#"a"
	#"\n"

Text (implemented as java.lang.String)

	"yolo"
	"Hello\nWorld!"

Forms

	(+ 1 2)
	(lambda [x] (foo 10 x))

Symbols

	foo     ## Unprefixed symbol (compiler will assume it's in the current module)
	bar;baz ## Prefixed symbol (compiler will assume it's in the module specified by the prefix)
	;fold   ## With just the semi-colon, compiler wil assume it's the same as lux;fold
	;;quux  ## With 2 semi-colons, it will get automatically prefixed with the current-module

Tags

	#Nil
	#lux;Cons
	#;Some
	#;;MyTag

Tuples

	[]
	["yolo" 10 true]

Variants (aka sum-types, aka discriminated unions)

	#Nil
	(#Cons [10 #Nil])

Records

	{#name "Eduardo" #alive? true}

### Types
	(deftype Bool (^ java.lang.Boolean))

	(deftype Int (^ java.lang.Long))

	(deftype Real (^ java.lang.Double))

	(deftype Char (^ java.lang.Character))

	(deftype Text (^ java.lang.String))

	(deftype Void (|))

	(deftype Ident (, Text Text))

	(deftype (List a)
	  (| #Nil
		 (#Cons [a (List a)])))

	(deftype (Maybe a)
	  (| #None
		 (#Some a)))

	(deftype Type ...)

	(deftype (Meta m d)
	  (| (#Meta [m d])))

	(deftype Syntax ...)

	(deftype (Either l r)
	  (| (#Left l)
		 (#Right r)))

	(deftype Reader ...)

	(deftype LuxVar ...)

	(deftype CompilerState ...)

	(deftype (Lux a)
	  (-> CompilerState (Either Text (, CompilerState a))))

	(deftype Macro
	  (-> (List Syntax) (Lux (List Syntax))))

	(deftype (IO a)
	  (-> (,) a))

### Macros
###### defmacro
e.g.

	(defmacro #export (and tokens)
	  (case (reverse tokens)
		(\ (list& last init))
		(return (: (List Syntax)
		           (list (fold (: (-> Syntax Syntax Syntax)
		                          (lambda [post pre]
		                            (` (if (~ pre)
		                                 true
		                                 (~ post)))))
		                       last
		                       init))))
		
		_
		(fail "and requires >=1 clauses.")))

###### comment
e.g.

	(comment 1 2 3 4) ## Same as not writing anything...

###### list
e.g.

	(list 1 2 3)
	=> (#Cons [1 (#Cons [2 (#Cons [3 #Nil])])])

###### list&
e.g.

	(list& 0 (list 1 2 3))
	=> (#Cons [0 (list 1 2 3)])

###### lambda
e.g.

	(def const
	  (lambda [x y] x))

	(def const
	  (lambda const [x y] x))

###### let
e.g.
	(let [x (foo bar)
		  y (baz quux)]
	  ...)

###### $
e.g.

	## Text/string concatenation
	($ text:++ "Hello, " name ".\nHow are you?")
	=> (text:++ "Hello, " (text:++ name ".\nHow are you?"))

###### |>
e.g.

	## Piping macro
	(|> elems (map ->text) (interpose " ") (fold text:++ ""))
	=>
	(fold text:++ ""
		  (interpose " "
		             (map ->text elems)))

###### if
e.g.

	(if true
	  "Oh, yeah"
	  "Aw hell naw!")

###### ^
e.g.

	## Macro to treat classes as types
	(^ java.lang.Object)

###### ,
e.g.

	## Tuples
	(, Text Int Bool)
	
	(,) ## The empty tuple, aka "unit"

###### |
e.g.

	(| #Yes #No)
	
	(,) ## The empty variant, aka "void"

###### &
e.g.

	## Records
	(& #name Text
	   #age Int
	   #alive? Bool)

###### ->
e.g.
	
	## Function types
	(-> Int Int Int) ## This is the type of a function that takes 2 Ints and returns an Int

###### All
e.g.

	## Universal quantification.
	(All List [a]
		 (| #Nil
		    (#Cons [a (List a)])))

	## It must be explicit, unlike in Haskell. Rank-n types will be possible as well as existential types
	(All [a]
	  (-> a a))

###### type`

	## This macro is not meant to be used directly. It's used by :, :!, deftype, struct, sig

###### io

	## Just makes sure whatever computation you do returns an IO type. It's here mostly for host-interop.

###### :
e.g.

	## The type-annotation macro
	(: (List Int) (list 1 2 3))

###### :!
e.g.

	## The type-coercion macro
	(:! Dinosaur (list 1 2 3))

###### deftype
e.g.

	## The type-definition macro
	(deftype (List a)
	  (| #Nil
		 (#Cons [a (List a)])))

###### exec
e.g.

	## Sequential execution of expressions (great for side-effects).
	## But please use the io macro to help keep the purity.
	(exec
	  (println "#1")
	  (println "#2")
	  (println "#3")
	  "YOLO")

###### def
e.g.

	## Macro for definining global constants/functions.
	(def (rejoin-pair pair)
	  (-> (, Syntax Syntax) (List Syntax))
	  (let [[left right] pair]
		(list left right)))

###### case
e.g.

	## The pattern-matching macro.
	## Allows the usage of macros within the patterns to provide custom syntax.
	(case (: (List Int) (list 1 2 3))
	  (#Cons [x (#Cons [y (#Cons [z #Nil])])])
	  (#Some ($ int:* x y z))

	  _
	  #None)

	(case (: (List Int) (list 1 2 3))
	  (\ (list 1 2 3))
	  (#Some ($ int:* x y z))

	  _
	  #None)

	(deftype Weekday
	  (| #Monday
		 #Tuesday
		 #Wednesday
		 #Thursday
		 #Friday
		 #Saturday
		 #Sunday))

	(def (weekend? day)
	  (-> Weekday Bool)
	  (case day
		(\or #Saturday #Sunday)
		true

		_
		false))

###### \

	## It's a special macro meant to be used with case

###### \or

	## It's a special macro meant to be used with case

###### `

	## Quasi-quotation as a macro. Unquote (~) and unquote-splice (~@) must also be used as forms
	e.g.
	(` (def (~ name)
		 (lambda [(~@ args)]
		   (~ body))))

###### sig

	## Not mean to be used directly. Prefer defsig

###### struct

	## Not mean to be used directly. Prefer defstruct

###### defsig
e.g.

	## Definition of signatures ala ML
	(defsig #export (Ord a)
	  (: (-> a a Bool)
		 <)
	  (: (-> a a Bool)
		 <=)
	  (: (-> a a Bool)
		 >)
	  (: (-> a a Bool)
		 >=))

###### defstruct
e.g.

	## Definition of structures ala ML
	(defstruct #export Int:Ord (Ord Int)
	  (def (< x y)
		(jvm-llt x y))
	  (def (<= x y)
		(or (jvm-llt x y)
		    (jvm-leq x y)))
	  (def (> x y)
		(jvm-lgt x y))
	  (def (>= x y)
		(or (jvm-lgt x y)
		    (jvm-leq x y))))

###### and
e.g.

	(and true false true) ## => false

###### or
e.g.

	(or true false true) ## => true

###### alias-lux

	## Just creates local aliases of everything defined & exported in lux.lux
e.g.

	(;alias-lux)

###### using
e.g.

	## The Lux equivalent to ML's open.
	## Opens up a structure and provides all the definitions as local variables.
	(using Int:Ord
	  (< 5 10))

### Functions
###### fold

	(All [a b]
	  (-> (-> a b a) a (List b) a))

###### reverse

	(All [a]
	  (-> (List a) (List a)))

###### map

	(All [a b]
	  (-> (-> a b) (List a) (List b)))

###### any?

	(All [a]
	  (-> (-> a Bool) (List a) Bool))

.

	## Function composition: (. f g) => (lambda [x] (f (g x)))
	(All [a b c]
	  (-> (-> b c) (-> a b) (-> a c)))

###### int:+

	(-> Int Int Int)

###### int:-

	(-> Int Int Int)

###### int:*

	(-> Int Int Int)

###### int:/

	(-> Int Int Int)

###### int:%

	(-> Int Int Int)

###### int:=

	(-> Int Int Bool)

###### int:>

	(-> Int Int Bool)

###### int:<

	(-> Int Int Bool)

###### real:+

	(-> Real Real Real)

###### real:-

	(-> Real Real Real)

###### real:*

	(-> Real Real Real)

###### real:/

	(-> Real Real Real)

###### real:%

	(-> Real Real Real)

###### real:=

	(-> Real Real Bool)

###### real:>

	(-> Real Real Bool)

###### real:<

	(-> Real Real Bool)

###### length

	## List length
	(All [a]
	  (-> (List a) Int))

###### not

	(-> Bool Bool)

###### text:++

	## Text/string concatenation
	(-> Text Text Text)

###### get-module-name

	## Obtain the name of the currently-compiling module while in a macro.
	(Lux Text)

###### find-macro

	## Given the name of a macro, try to obtain it.
	(-> Ident (Lux (Maybe Macro)))

###### normalize

	## Normalizes a name so if it lacks a module prefix, it gets the one of the current module.
	(-> Ident (Lux Ident))

###### ->text

	(-> (^ java.lang.Object) Text)

###### interpose

	(All [a]
	  (-> a (List a) (List a)))

###### syntax:show

	## Turn Lux synta into user-readable text. (Note: it's not pretty-printed)
	(-> Syntax Text)

###### macro-expand

	## The standard macro-expand function.
	(-> Syntax (Lux (List Syntax)))

###### gensym

	## Can't forget gensym!
	(-> Text (Lux Syntax))

###### macro-expand-1

	(-> Syntax (Lux Syntax))

###### id

	(All [a] (-> a a))

###### print

	## Neither print or println return IO right now because I've yet to implement monads & do-notation
	## Note: The implementation inside lux.lux is not meant for public consumption.
	## Note: You'll get an implementation of monads, functors et al. soon enough...
	(-> Text (,))

###### println

	(-> Text (,))

###### some

	(All [a b]
	  (-> (-> a (Maybe b)) (List a) (Maybe b)))

### Signatures
###### Eq

	(defsig #export (Eq a)
	  (: (-> a a Bool)
		 =))

###### Show

	(defsig #export (Show a)
	  (: (-> a Text)
		 show))

###### Ord

	(defsig #export (Ord a)
	  (: (-> a a Bool)
		 <)
	  (: (-> a a Bool)
		 <=)
	  (: (-> a a Bool)
		 >)
	  (: (-> a a Bool)
		 >=))

### Structures
###### Int:Eq
###### Real:Eq

###### Bool:Show
###### Int:Show
###### Real:Show
###### Char:Show

###### Int:Ord
###### Real:Ord

## Caveats

### Errors
The compiler is not fully stable so you might get an error if you do anything funny.

Also, the error messages could really use an overhaul, so any error message you get will probably startle you.

Don't worry about it, version 0.2 will improve error reporting a lot.
If you have any doubts, feel free to ask/complain in the Google Group.

### Tags

Tags that are unprefixed will just assume the prefix of the current module you're in.

If you want to write variants/records with tags from lux.lux, you must do 1 of the following 2 alternatives:

* Fully prefix them: #lux;Cons
* Use the ; short-cut: #;Cons

##### Copyright (c) 2015 Eduardo Julian. All rights reserved.