summaryrefslogtreecommitdiffhomepage
path: root/livescript.html.markdown
blob: 2c72df0a9784ad18fde278fc4409bf29570accdd (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
---
language: LiveScript
filename: learnLivescript.ls
contributors:
    - ["Christina Whyte", "http://github.com/kurisuwhyte/"]
---

LiveScript is a functional compile-to-JavaScript language which shares
most of the underlying semantics with its host language. Nice additions
comes with currying, function composition, pattern matching and lots of
other goodies heavily borrowed from languages like Haskell, F# and
Scala.

LiveScript is a fork of [Coco][], which is itself a fork of
[CoffeeScript][]. The language is stable, and a new version is in active
development to bring a plethora of new niceties!

[Coco]: http://satyr.github.io/coco/
[CoffeeScript]: http://coffeescript.org/

Feedback is always welcome, so feel free to reach me over at
[@kurisuwhyte](https://twitter.com/kurisuwhyte) :)


```livescript
# Just like its CoffeeScript cousin, LiveScript uses hash symbols for
# single-line comments.

/*
 Multi-line comments are written C-style. Use them if you want comments
 to be preserved in the JavaScript output.
 */

# As far as syntax goes, LiveScript uses indentation to delimit blocks,
# rather than curly braces, and whitespace to apply functions, rather
# than parenthesis.


########################################################################
## 1. Basic values
########################################################################

# Lack of value is defined by the keyword `void` instead of `undefined`
void            # same as `undefined` but safer (can't be overridden)

# No valid value is represented by Null.
null


# The most basic actual value is the logical type:
true
false

# And it has a plethora of aliases that mean the same thing:
on; off
yes; no


# Then you get numbers. These are double-precision floats like in JS.
10
0.4     # Note that the leading `0` is required

# For readability, you may use underscores and letter suffixes in a
# number, and these will be ignored by the compiler.
12_344km


# Strings are immutable sequences of characters, like in JS:
"Christina"             # apostrophes are okay too!
"""Multi-line
   strings
   are
   okay
   too."""

# Sometimes you want to encode a keyword, the backslash notation makes
# this easy:
\keyword                # => 'keyword'


# Arrays are ordered collections of values.
fruits =
  * \apple
  * \orange
  * \pear

# They can be expressed more concisely with square brackets:
fruits = [ \apple, \orange, \pear ]

# You also get a convenient way to create a list of strings, using
# white space to delimit the items.
fruits = <[ apple orange pear ]>

# You can retrieve an item by their 0-based index:
fruits[0]       # => "apple"

# Objects are a collection of unordered key/value pairs, and a few other
# things (more on that later).
person =
  name: "Christina"
  likes:
    * "kittens"
    * "and other cute stuff"

# Again, you can express them concisely with curly brackets:
person = {name: "Christina", likes: ["kittens", "and other cute stuff"]}

# You can retrieve an item by their key:
person.name     # => "Christina"
person["name"]  # => "Christina"


# Regular expressions use the same syntax as JavaScript:
trailing-space = /\s$/          # dashed-words become dashedWords

# Except you can do multi-line expressions too!
# (comments and whitespace just gets ignored)
funRE = //
        function\s+(.+)         # name
        \s* \((.*)\) \s*        # arguments
        { (.*) }                # body
        //


########################################################################
## 2. Basic operations
########################################################################

# Arithmetic operators are the same as JavaScript's:
1 + 2   # => 3
2 - 1   # => 1
2 * 3   # => 6
4 / 2   # => 2
3 % 2   # => 1


# Comparisons are mostly the same too, except that `==` and `===` are
# inverted.
2 == 2          # => true
2 == "2"        # => false
2 === "2"       # => true

# Other relational operators include <, <=, > and >=

# Logical values can be combined through the logical operators `or`,
# `and` and `not`
true and false  # => false
false or true   # => true
not false       # => true


# Collections also get some nice additional operators
[1, 2] ++ [3, 4]                # => [1, 2, 3, 4]
'a' in <[ a b c ]>              # => true
'name' of { name: 'Chris' }     # => true


########################################################################
## 3. Functions
########################################################################        

# Since LiveScript is functional, you'd expect functions to get a nice
# treatment. In LiveScript it's even more apparent that functions are
# first class:
add = (left, right) -> left + right
add 1, 2        # => 3

# Functions which take no arguments are called with a bang!
two = -> 2
two!

# LiveScript uses function scope, just like JavaScript, and has proper
# closures too. Unlike JavaScript, the `=` works as a declaration
# operator, and will always declare the variable on the left hand side.

# The `:=` operator is available to *reuse* a name from the parent
# scope.


# You can destructure arguments of a function to quickly get to
# interesting values inside a complex data structure:
tail = ([head, ...rest]) -> rest
tail [1, 2, 3]  # => [2, 3]

# You can also transform the arguments using binary or unary
# operators. Default arguments are also possible.
foo = (a = 1, b = 2) -> a + b
foo!    # => 3

# You could use it to clone a particular argument to avoid side-effects,
# for example:
copy = (^^target, source) ->
  for k,v of source => target[k] = v
  target
a = { a: 1 }
copy a, { b: 2 }        # => { a: 1, b: 2 }
a                       # => { a: 1 }


# A function may be curried by using a long arrow rather than a short
# one:
add = (left, right) --> left + right
add1 = add 1
add1 2          # => 3

# Functions get an implicit `it` argument, even if you don't declare
# any.
identity = -> it
identity 1      # => 1

# Operators are not functions in LiveScript, but you can easily turn
# them into one! Enter the operator sectioning:
divide-by-2 = (/ 2)
[2, 4, 8, 16].map(divide-by-2) .reduce (+)


# Not only of function application lives LiveScript, as in any good
# functional language you get facilities for composing them:
double-minus-one = (- 1) . (* 2)

# Other than the usual `f . g` mathematical formulae, you get the `>>`
# and `<<` operators, that describe how the flow of values through the
# functions. 
double-minus-one = (* 2) >> (- 1)
double-minus-one = (- 1) << (* 2)


# And talking about flow of value, LiveScript gets the `|>` and `<|`
# operators that apply a value to a function:
map = (f, xs) --> xs.map f
[1 2 3] |> map (* 2)            # => [2 4 6]

# You can also choose where you want the value to be placed, just mark
# the place with an underscore (_):
reduce = (f, xs, initial) --> xs.reduce f, initial
[1 2 3] |> reduce (+), _, 0     # => 6


# The underscore is also used in regular partial application, which you
# can use for any function:
div = (left, right) -> left / right
div-by-2 = div _, 2
div-by-2 4      # => 2


# Last, but not least, LiveScript has back-calls, which might help
# with some callback-based code (though you should try more functional
# approaches, like Promises):
readFile = (name, f) -> f name
a <- readFile 'foo'
b <- readFile 'bar'
console.log a + b

# Same as:
readFile 'foo', (a) -> readFile 'bar', (b) -> console.log a + b


########################################################################
## 4. Patterns, guards and control-flow
########################################################################

# You can branch computations with the `if...else` expression:
x = if n > 0 then \positive else \negative

# Instead of `then`, you can use `=>`
x = if n > 0 => \positive
    else        \negative

# Complex conditions are better-off expressed with the `switch`
# expression, though:
y = {}
x = switch
  | (typeof y) is \number => \number
  | (typeof y) is \string => \string
  | 'length' of y         => \array
  | otherwise             => \object      # `otherwise` and `_` always matches.

# Function bodies, declarations and assignments get a free `switch`, so
# you don't need to type it again:
take = (n, [x, ...xs]) -->
                        | n == 0 => []
                        | _      => [x] ++ take (n - 1), xs


########################################################################
## 5. Comprehensions
########################################################################

# While the functional helpers for dealing with lists and objects are
# right there in the JavaScript's standard library (and complemented on
# the prelude-ls, which is a "standard library" for LiveScript),
# comprehensions will usually allow you to do this stuff faster and with
# a nice syntax:
oneToTwenty = [1 to 20]
evens       = [x for x in oneToTwenty when x % 2 == 0]

# `when` and `unless` can be used as filters in the comprehension.

# Object comprehension works in the same way, except that it gives you
# back an object rather than an Array:
copy = { [k, v] for k, v of source }


########################################################################
## 4. OOP
########################################################################

# While LiveScript is a functional language in most aspects, it also has
# some niceties for imperative and object oriented programming. One of
# them is class syntax and some class sugar inherited from CoffeeScript:
class Animal
  (@name, kind) ->
    @kind = kind
  action: (what) -> "*#{@name} (a #{@kind}) #{what}*"

class Cat extends Animal
  (@name) -> super @name, 'cat'
  purr: -> @action 'purrs'

kitten = new Cat 'Mei'
kitten.purr!      # => "*Mei (a cat) purrs*"

# Besides the classical single-inheritance pattern, you can also provide
# as many mixins as you would like for a class. Mixins are just plain
# objects:
Huggable =
  hug: -> @action 'is hugged'

class SnugglyCat extends Cat implements Huggable

kitten = new SnugglyCat 'Purr'
kitten.hug!     # => "*Mei (a cat) is hugged*"
```

## Further reading

There's just so much more to LiveScript, but this should be enough to
get you started writing little functional things in it. The 
[official website](http://livescript.net/) has a lot of information on the
language, and a nice online compiler for you to try stuff out!

You may also want to grab yourself some
[prelude.ls](http://gkz.github.io/prelude-ls/), and check out the `#livescript`
channel on the Freenode network.