slick-lang v5.3.0
Slick
Introduction
Slick is a statically typed functional programming language transpiled to JavaScript.
Slick aims to unclutter software development and is heavily influenced by Elm and Neo.
Slick is an experimental language and is not intended to be used in production. However, contributions are always welcome! ๐
Hello World
_ :
print 'Hello World!'_ is the placeholder symbol for a binding name. You can repeatedly use _ in your code to render side effects such as printing to the console.
print is the built-in function to print any value to standard output.
Function invocations use space to separate callee and arguments instead of parentheses to avoid parenthesis hell.
Comments
# Slick only has single-line comments
# Combine multiple
# single-line comments
# to form a multi-line commentPrimitive Types
Slick only has three primitive types:
Num
How are numbers represented?
Numbers in Slick are all arbitrary precision (by default to 20 significant figures) floating point numbers. There is not separate integer type to avoid type complexity and unnecessary type conversion between integers and floats. Unlike most languages, Slick does not suffer from floating point rounding errors so all calculations are accurate up to 20 significant figures. (you can change the number of sig figs in the compiler setting in the future).
How can I work with Num?
Infix operators:
+, -, *, / for add, subtract, multiply, and divide
% for modulo (getting the remainder of dividing two numbers)Math functions see reference.
Text
Texts in Slick are lists of Unicode codepoints surrounded with 's (single quotes).
Why no char type?
Unlike languages like C and Java, Slick does not have a char type because one user-perceived character like 'รฑ' may consists of multiple Unicode codepoints (n+โฬ ) thus a character needs to be stored as a list of codepoints. A list of Unicode codepoints is exactly what Text is so there's no point in creating a separate type.
How can I work with Text?
You still have all the familiar operations like slice and length but they now have user-perceived characters as unite of operation instead of Unicode codepoints. So calling length on เค
เคจเฅเคเฅเคเฅเคฆ returns 5 because the text contains just 5 user-perceived characters (เค
+ เคจเฅ + เคเฅ + เคเฅ + เคฆ) instead of 8 Unicode codepoints (เค
+ เคจ + เฅ + เค + เฅ + เค + เฅ + เคฆ). The rules for splitting text into user-perceived characters follows the Unicode standard UAX #29.
You can concatenate two texts using &:
print ('Hello ' & 'world!') # Hello world!Bool
Booleans in Slick are either True or False.
How can I work with Bool?
True โ False = False # ('โ' for and operator)
True โ False = True # ('โ' for or operator)In the code editor, type /\ to create โ and \/ to create โ.
Bindings
name :
'Bob'Bindings are immutable. The value of the binding must be on the next line after the : (colon) for consistent code style. Function expression is an exception. Function header must be on the same line as the :.
# Valid binding names
foo
longBindingNme
# Invalid binding names
long_binding_name # Use camelCase instead of '_'
$bindingName # No symbols other than '?' are permitted
Foo # binding name can only start with lowercase
# uppercase reserved for type namesFunctions
add : ฦ a b
a + bAll functions in slick are expressions and starts with the ฦ symbol. Notice that the ฦ is italic, not a normal f. You can use keyboard shorthand \f in the code editor to type ฦ (see how to install Slick VS Code extension). Put any parameters after ฦ and separate each with a space. The function body is an expression and Slick evaluates that expression to produce the function return value.
add = Num โ Num โ Num
add : ฦ a b
a + bWe recommend putting a type declaration above the function. Adding type declaration both confirms that the type you think the function possesses is correct and serves as compiler-verified documentation for the function. In Slick, we don't specially highlight the return type of the function in its type declaration. Instead, we chain all parameter types and the return type together with โ (keyboard shorthand -> ). The reason for this is because all functions in Slick are curried and the โ separated type declaration allows partial applications on all functions.
Another way to declare short functions is to surround the function body with () without a line break after the function header:
add = Num โ Num โ Num
add : ฦ a b (a + b)Records
bob :
{
name : 'Bob'
age: 45
employeed: True
}Record maps a Text key to a value of any type. No duplicate keys are allowed.
You can access record property using the . (dot) operator
# 'Bob'
name :
bob.nameRecords are immutable. Use | (bar) to update record property:
alice :
{
bob |
name : 'Alice'
}The alice record is created by updating the name property of record bob to 'Alice'.
Lists
list:
[1, 2, 3]Lists are immutable and can only contain values of same type.
Here we will only give a simple example. Refer to the API documentation in the end for more details.
Create a list of even numbers from 1 to 10:
evenList :
List.filter # calls the List.filter function
ฦ element (element % 2 = 0) # keep only even elements in the list
(List.range 1 10) # create a list ranging from 1 to 10Notice that function calls can span multiple lines. Here we are calling List.filter function with a function that keeps even elements and a list produced by List.range.
If Expression
value :
0
valueName :
if value > 0
'positive'
elif value = 0
'zero'
else
'negative'
_ :
# outputs 'value is zero'
print ('value is ' & valueName)
Type Aliases
Slick is all about data structures. All program states are stored using data structures (or Abstract Data Types, ADTs). Sometimes you may find yourself repeat the type names of an ADT as you use them throughout the program, then it's the time to introduce a type alias for that ADT.
# Grid stands for a 2-dimensional list of numbers
type alias Grid :
List List NumType aliases help maintain the DRY (Don't Repeat Yourself) principle in your code and make refactoring the ADT much easier later.
Custom Types
Primitive data types - Bool, Text, and Num - usually do the job. However, many properties do not fit nicely into the three primitive types. For example, you may want to represent day of the week in your program. At first, you may be tempted to just settle with Text:
dayOfWeek :
'Friday'However, too many things that are not day of week can be stored in Text :
dayOfWeek :
'hello'You may be satisfied with using the Text representation until you want to convert dayOfWeek to a number:
dayOfWeek :
'monday'
dayNumber :
if dayOfWeek = 'Sunday' then
0
elif dayOfWeek = 'Monday' then
1
elif dayOfWeek = 'Tuesday' then
2
elif dayOfWeek = 'Wednesday' then
3
elif dayOfWeek = 'Thursday' then
4
elif dayOfWeek = 'Friday' then
5
else
6Now there are a lot of elifs and thens. Let's simplify this if-elif-else chain with case expression.
dayOfWeek :
'monday'
dayNumber :
case dayOfWeek of
'Sunday' โ
0
'Monday' โ
1
'Tuesday' โ
2
'Wednesday' โ
3
'Thursday' โ
4
'Friday' โ
5
_ โ
6What we did is basically extracting the dayOfWeek binding to the top of the case expression, remove the if, elifs, and elses, and replace then with โ. Notice the last _ (underscore) placeholder? That just means else.
All looks good but oops! All of a sudden, dayNumber yields 6 when dayOfWeek is monday instead of the correct result 1 because monday โ Monday and we drop all the way to the bottom _ catch-all else case. This kind of bug is also very hard to catch because the programming logic is perfect except for a single character.
Is this the best we can do?
No!
Enter custom types ๐๐๐
You can create a custom DayOfWeek type to precisely capture all seven days of the week with no room for invalid states:
type DayOfWeek :
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
SaturdayWell, what's special about this? Now, you can't need to worry about invalid day of week because they are impossible! The Slick compiler checks it for you to make sure the integrity of the custom type. Let's rewrite the dayNumber using new the custom type DayOfWeek:
dayOfWeek :
# 'monday' or 'Monday' no longer works because now dayOfWeek is a custom type, not a Text
Monday
dayNumber :
case dayOfWeek of
Sunday โ
0
Monday โ
1
Tuesday โ
2
Wednesday โ
3
Thursday โ
4
Friday โ
5
# if you omit any one DayOfWeek, Slick will not compile the code
Saturday โ
6Case Expression
Here's another simple example of how to use case expression on custom types:
type Fruit :
Apple
Banana
Orange
fruit :
Banana
# 0.75
fruitPrice :
case fruit of
Apple โ
2
Banana โ
0.75
Orange โ
1.5Install Slick
Create a new npm project using:
npm initNow your project tree should look like:
package-lock.json
package.jsonCreate a src folder:
src/
package-lock.json
package.jsonAdd helloWorld.slk to the src folder:
# helloWorld.slk
_ :
print 'Hello World from Slick!'Your project should now look like:
src/
|- helloWorld.slk
package-lock.json
package.jsonInstall the slick compiler:
npm install slick-makeNow your project tree should have a node_modules folder added by npm:
node_modules/
src/
|- helloWorld.slk
package-lock.json
package.jsonIn your package.json, add a scripts property:
"scripts": {
"slick": "node node_modules/slick-make/dist/cli.js"
}Run you slick program:
npm run slick run src/helloWorld.slkHello World from Slick!๐๐๐ Congratulation! You just ran you first Slick program!
See the examples folder for more examples.
Set up Slick in Visual Studio Code
Install slick-vscode-extension and you are all set with full syntax highlighting and symbol shorthands.

Symbol Shorthands
| You type | to get |
|---|---|
\f | ฦ |
-> | โ |
>= | โฅ |
<= | โค |
!= | โ |
/\ |โ | |
\/ | โ |
API functions
Text functions
lower Text โ Text
upper Text โ Text
lower? Text โ Bool
upper? Text โ Bool
nth Num โ Text โ Maybe Text
take Num โ Text โ Text
takeLast Num โ Text โ Text
trim Text โ Text
split Text โ Text โ List Text
capitalize Text โ Text
endsWith Text โ Text โ Bool
startsWith Text โ Text โ Bool
slice Num โ Num โ Text โ Text
member Text โ Text โ Bool
length Text โ Num
char Num โ Maybe Text
join Text โ List Text โ TextList functions
map (a โ b) โ List a โ List b
mapIndexed (a โ Num โ b) โ List a โ List b
filter (a โ Bool) โ List a โ List a
reject (a โ Bool) โ List a โ List a
find (a โ Bool) โ List a โ Maybe a
reduce (a โ b โ a) โ a โ List b โ a
reduceLast (a โ b โ a) โ a โ List b โ a
all (a โ Bool) โ List a โ Bool
any (a โ Bool) โ List a โ Bool
first List a โ Maybe a
tail List a โ List a
head List a โ List a
last List a โ Maybe a
nth Num โ List a โ Maybe a
take Num โ List a โ List a
takeLast Num โ List a โ List a
slice Num โ Num โ List a โ List a
member a โ List a โ Bool
insert Num โ a โ List a โ List a
append a โ List a โ List a
prepend a โ List a โ List a
update Num โ a โ List a โ List a
drop Num โ List a โ List a
dropLast Num โ List a โ List a
concat List a โ List a โ List a
adjust Num โ (a โ a) โ List a โ List a
length List a โ Num
range Num โ Num โ List Num
sum List Num โ NumNum functions
abs Num โ Num
max Num โ Num โ Num
min Num โ Num โ Num
neg Num โ Num
sqrt Num โ Num
round Num โ Num
floor Num โ Num
ceil Num โ Num
trunc Num โ Num
pi Num
e Num
sin Num โ Num
cos Num โ Num
tan Num โ Num
asin Num โ Num
acos Num โ Num
atan Num โ Num
atan2 Num โ Num โ Numother built-in functions
not Bool โ Bool
print a โ Text6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago