$ npm install -g LiveScriptStart LiveScript REPL:
$ lsc -dvar double = function(x) {
return x * 2
}Functions are fundamental pieces of programming and math. But they're unnecessary verbose in JavaScript.
In LiveScript:
double = (x) -> x * 2In JavaScript:
var twenty = double(10)In LiveScript:
twenty = double 10evens = [1,2,3,4,5,6,7,8,9,10].filter(function(x) {
return x % 2 == 0
});ls> evens = [1 to 10].filter (x) -> x % 2 == 0
[2,4,6,8,10]doubleSmallNumber = function(n) {
return (n < 100) ? n * 2 : n;
}double-small-number = (n) -> if n < 100 then n * 2 else nConcatenating two arrays:
ls> [1,2,3,4] ++ [9,10,11,12]
[1,2,3,4,9,10,11,12]Empty arrays:
ls> [] ++ [1, 2, 3]
[1, 2, 3]ls> head [1 to 10]
1
ls> tail [1 to 10]
[2,3,4,5,6,7,8,9,10]ls> take 3, [5,4,3,2,1]
[5,4,3]
ls> drop 3, [8,4,2,1,5,6]
[1,5,6]ls> minimum [8,4,2,1,5,6]
1
ls> maximum [1,9,2,3,4]
9There are many more functions on lists, including: sum, product, mean, union, intersection and many more. We'll take a look at more list function later.
ls> [x * 2 for x in [1 to 10]]
[2,4,6,8,10,12,14,16,18,20]ls> [x * x for x to 10 when (x `mod` 2) != 0]
[1,9,25,49,81]ls> [x * y for x in [2,5,10] for y in [8,10,11] when x * y > 50]
[55,80,100,110]Let's write a length function on lists:
ls> length = (xs) -> sum [1 for _ in xs]
ls> length [100 to 150]
51ls> numbers = [1, 2, 3, 4]
ls> words = ['One', 'Two', 'Three', 'Four']
ls> zip numbers, words
[[1,"One"],[2,"Two"],[3,"Three"],[4,"Four"]]zip takes two lists and produces a list of pairs.
It's more intuitive to infix the zip function (it's zip after all):
ls> numbers `zip` wordsls> [head, ...rest] = ['A', 'B', 'C', 'D', 'E', 'F'] ls> [a, b, c, ...rest] = ['A', 'B', 'C', 'D', 'E', 'F']
ls> [head, ..., last] = ['A', 'B', 'C', 'D', 'E', 'F']
ls> user = {name: 'John', language: 'en', id: 31245}
ls> {language} = user
ls> language
"en"length = ([x, ...xs]:list) -> match list
| [] => 0
| _ => 1 + length xs
length [1 to 10]sum = ([x, ...xs]:list) -> match list
| [] => 0
| _ => x + sum xs
sum [1 to 10]minimum = ([x, ...xs]:list, min = x) -> match list
| [] => min
| _ => minimum xs, (Math.min x, min)
minimum [Math.random! for _ in [1 to 10]]Parameter min has a default values that is equal to the first element of the list (x) if not provided. Note that in the recursive call we pass the current minimum as for min.
map = (f, [x, ...xs]:list) -> match list
| [] => []
| _ => [f x] ++ map f, xs
map (* 2), [1 to 10]filter = (f, [x, ...xs]:list) -> match list
| [] => []
| _ => (if f x then [x] else []) ++ filter f, xs
filter odd, [1 to 10]reverse = ([x, ...xs]:list) -> match list
| [] => []
| _ => (reverse xs) ++ [x]
reverse [1 to 10]group-by = (f, [x, ...xs]:list, result = {}) -> match list
| [] => result
| _ =>
key = f x
result[key] ?= [] # assign result[key] to empty array if it is not defined
result[key].push x
group-by f, xs, result
group-by (.length), ['one', 'two', 'three']General pattern:
foldr = (aggregator, zero, [x, ...xs]:list) -> match list
| [] => zero
| _ => aggregator x, (foldr aggregator, zero, xs)map = (f, xs) -> foldr ((a, acc) -> [f a] ++ acc), [], xs
filter = (f, xs) -> foldr ((a, acc) -> (if f a then [a] else []) ++ acc), [], xs
sum = (xs) -> foldr ((a, acc) -> a + acc), 0, xs
sum = (xs) -> foldr (+), 0, xsfact = (n) ->
return undefined if n < 1
return 1 if n == 1
n * fact n - 1 Using match:
fact = (n) -> match n
| (< 1) => undefined
| 1 => 1
| otherwise => n * fact n - 1 ls> add = (x, y) --> x + yls> add5 = add 5
ls> add5 7 # == 12 ; add5 = (y) -> 5 + ydouble = (x) -> x * 2
double = (* 2)
map ((x) -> double x), [1 to 10]
map (-> double it), [1 to 10]
map double, [1 to 10]
f = (x) -> sin x
g = (x) -> abs x
f . g # == (x) -> f (g x) == sin (abs x)
Eta reduced:
sin . abs = (x) -> sin (abs x)
sumf = (f, [x, ...xs]:list) -> match list
| empty => 0
| _ => (f x) + sumf f, xssumf = (f, xs) --> sum (map f, xs)
sumf = sum . map
sumf = sum << map
sumf = map >> sum
list = [{x: 2}, {x: 11}, {x: 13}, {x: 4}]
sumf (.x), list # == 30
By currying foldr function:
foldr = (aggregator, zero, [x, ...xs]:list) --> match list
| empty => zero
| otherwise => aggregator x, (foldr aggregator, zero, xs)sum = (xs) -> foldr ((a, acc) -> a + acc), 0, xs
sum = (xs) -> foldr (+), 0, xs
sum = foldr (+), 0The argument of a function can be piped to it from left
2 |> double # == double 2
Or right:
double <| sin pi/2 # == double (sin pi/2)
[1 to 10]
|> map double
|> sum
|> (* -1)
# == -110
zero = (f, z) --> z
one = (f, z) --> z |> f
two = (f, z) --> z |> f . f
three = (f, z) --> z |> f . f . f
four = (f, z) --> z |> f . f . f . fNatural number n representation in Church numeral is equivalent to n application of a function (f) starting from (f z) for one.
church-to-int function converts a Church numeral to its integer representation:
church-to-int = (c) -> c (+ 1), 0Try it out: church-to-int four
We can think of four as:
four = (f, z) --> z |> f . f . f . f
four = (f, z) --> f (f . f . f) z
four = (f, z) --> f (z |> (f . f . f))
four = (f, z) --> f (three f, z)Similarly:
three = (f, z) --> f (two, f, z)
two = (f, z) --> f (one, f, z)
one = (f, z) --> f (zero, f, z)a
We can abstract away function incr that takes a Church number c and produces its successor:
incr = (c) ->
(f, z) --> f (c f, z)
incr applies f one more time to the value that was produced by c; hence incrementing the Church number.
It can be written in this form:
incr = (c) ->
(f, z) --> z |> f . c fc f is c times application of f
incr is a function that takes a Church numeral n and returns its successor that is also a Church numeral:
incr :: Church -> ChurchUsing incr we have can define our numerals this way:
zero = (f, z) --> z
one = incr zero
two = incr one
three = incr two
four = incr threeA Church numeral, whether it's zero, one or four or any other number, is a function with two parameters:
- A function (of type
a -> a, for any typea) - A default value (of type
athat is the value of thezero).
Church :: (a -> a) -> a -> a
two = ( f , z ) -> f (f z)Church numeral (for example two) applies f as many times as the value of the numeral (here two), each time passing the result of the previous application to f, starting from zero application of f (that is constant z).
We can define algebra using Church numerals:
add = (a, b) -->
(f, z) --> (b incr, a) f, zFirst note the type of add function:
add :: Church -> Church -> Church(f, z) --> (b incr, a) f, z is a new Church numeral.
b incr, a:
b is a Church numeral, hence a function of two parameters:
incrthat is a function of typea -> a, hereaitself is a Church numeral (a :: Church)- A default value (of type
aor hereChurch) that is Church numeralb
(b incr, a) means: call incr function as many times as the value of b, starting with default value a.
If b is zero, (b incr, a) is a
If b is one, (b incr, a) is incr a
If b is two, (b incr, a) is incr (incr a)
We can define multiplication as:
mult = (a, b) -->
(f, z) --> (b (add a), zero) f, zIn (b (add a), zero), b is a Church numeral that takes two parameters:
(add a)that is a function fromChurch -> Church- A default value
zero
(b (add a), zero) applies add a b times, starting from add a, zero, hence it is equivalent to b × a.
Similarly:
pow = (a, b) -->
(f, z) --> (b (mult a), one) f, zUsing eta rule, the definition of add, mult and pow can be reduced to:
add = (a, b) --> b incr, a
mult = (a, b) --> b (add a), zero
pow = (a, b) --> b (mult a), oneLet's give them a try:
church-to-int <| three `add` two
church-to-int <| (three `mult` two) `pow` (incr three)Begin with zero, and keep counting until n, but storing the last two numbers. Then when you get n, the previous one is its predecessor.
We first need a utility function suc which takes a tuple, ignores the first item in the tuple and returns a new tuple whose values are the second value of the input tuple and ints successor:
suc = ([_, b]) -> [b, incr b]Now:
dec = (b) ->
[x, _] = b suc, [undefined, zero]
xSimilar to add subtraction can be defined like this:
sub = (a, b) --> b dec, aFor example:
suc [undefined, one] |> map church-to-int
church-to-int <| dec four
church-to-int <| (four `pow` two) `sub` three