Change styles
This commit is contained in:
parent
301c8540b4
commit
5f5ae25060
@ -3,7 +3,8 @@ output: static
|
||||
template: static/template.html
|
||||
|
||||
headings:
|
||||
h1: text-4xl mb-4 font-black
|
||||
h2: text-3xl mt-8 mb-4 font-bold
|
||||
h3: text-2xl mt-8 mb-4 font-medium
|
||||
h1: text-3xl mb-4 font-display opacity-90
|
||||
h2: text-2xl mt-10 mb-4 font-display opacity-90
|
||||
h3: text-xl mt-10 mb-4 font-display opacity-90
|
||||
|
||||
file_tree_title_classes: "uppercase text-sm font-display"
|
||||
|
80
md/learn/basics/comments.md
Normal file
80
md/learn/basics/comments.md
Normal file
@ -0,0 +1,80 @@
|
||||
# Comments
|
||||
|
||||
You may have noticed that in some code examples there are some
|
||||
lines of text explaining the code:
|
||||
|
||||
```thp
|
||||
// This is the variable
|
||||
val person = "John"
|
||||
```
|
||||
|
||||
Comments are used to explain what the code does. Anything written
|
||||
in a comment is ignored by THP.
|
||||
|
||||
## Single line comments
|
||||
|
||||
As the name says, these comments span only 1 line. To create one write
|
||||
two slashes together `//`. Everything after the slashes and before
|
||||
the newline will be ignored.
|
||||
|
||||
```thp
|
||||
// This is a single line comment
|
||||
// You can write anything you want here, although it's usually
|
||||
// used to describe the code
|
||||
|
||||
// The commend ends where the line ends,
|
||||
so this line will not be ignored by THP, and will throw an error
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Multi line comments
|
||||
|
||||
As the name says, these comments can span multiple lines.
|
||||
|
||||
They have 2 components: a start and a end. To start a multiline comment
|
||||
write a slash and asterisk `/*`, and to end the comment, the inverse `*/`
|
||||
|
||||
```thp
|
||||
/*
|
||||
This is a multiline comment.
|
||||
I can write whatever I want here, and across multiple
|
||||
lines, as long as I'm before the closing characters (* /)
|
||||
*/
|
||||
```
|
||||
|
||||
|
||||
## Using comments to prevent code execution
|
||||
|
||||
Since comments are ignored by THP, we can use them to prevent certain
|
||||
parts of the code from running.
|
||||
|
||||
Let's say we have this script:
|
||||
|
||||
```thp
|
||||
print("Hello John")
|
||||
print("How's your day going?")
|
||||
```
|
||||
|
||||
If I wanted the 2nd line not to execute, I can use a comment:
|
||||
|
||||
```thp
|
||||
print("Hello John")
|
||||
// print("How's your day going?")
|
||||
```
|
||||
|
||||
Now the second line is ignored, and the message is not printed.
|
||||
|
||||
The same can be done with multiline comments.
|
||||
|
||||
|
||||
```thp
|
||||
print("Hello John")
|
||||
/*
|
||||
print("How's your day going?")
|
||||
*/
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
127
md/learn/basics/datatypes.md
Normal file
127
md/learn/basics/datatypes.md
Normal file
@ -0,0 +1,127 @@
|
||||
# Datatypes
|
||||
|
||||
Programming is comprised of 2 basic things: instructions and data.
|
||||
|
||||
If we compare a program to a cake recipe, the instructions are the steps
|
||||
(**pour** flour, **add** water, **add** egg, **mix**) and the data are the ingredients
|
||||
themselves (flour, water, egg).
|
||||
|
||||
![Image](Image)
|
||||
|
||||
Then, we can describe the recipe in terms of instructions and data. For example,
|
||||
"mix flour and egg to produce dough".
|
||||
|
||||
![Image](Image)
|
||||
|
||||
All code is like a recipe: A list of instructions and data that, when combined
|
||||
correctly, are able to transform a input to an output. Many advanced concepts
|
||||
are just ways to organize and abstract those instructions and data.
|
||||
|
||||
|
||||
## Classifying datatypes
|
||||
|
||||
As with food, datatypes can be classified. Just like there are fruits, vegetables,
|
||||
oils, there are `numbers`, `text`, `"booleans"`.
|
||||
|
||||
|
||||
|
||||
### Int
|
||||
|
||||
Int is an abbreviation for "integer numbers", which are numbers without a fractional component.
|
||||
They can be positive or negative.
|
||||
|
||||
In code, they are written just like numbers:
|
||||
|
||||
```thp
|
||||
val age = 33
|
||||
val children = 0
|
||||
val money = -15000
|
||||
```
|
||||
|
||||
You can use underscores to help you differentiate thousands, millions, etc.
|
||||
However, there cannot be spaces in between
|
||||
|
||||
```thp
|
||||
val studentDebt = 3_500_000_000_000 // Valid
|
||||
val invalid = 3 500 000 000 000 // Invalid, will throw an error
|
||||
```
|
||||
|
||||
The common operations can be done as in math:
|
||||
|
||||
```thp
|
||||
val result1 = 10 + 20
|
||||
val result2 = 1779 * 2 - (55 / 5)
|
||||
```
|
||||
|
||||
|
||||
### Float
|
||||
|
||||
Float is an abbreviation for "floating point numbers". In simplified terms, these are numbers
|
||||
**with** a fractional component.
|
||||
|
||||
They are written with a dot `.` to separate the whole part and the fraction.
|
||||
|
||||
```thp
|
||||
val pi = 3.141592
|
||||
val epsilon = 2.775557
|
||||
```
|
||||
|
||||
Underscore can also be used:
|
||||
|
||||
```thp
|
||||
val reallyLongNumber = 23_870_000.443_879
|
||||
```
|
||||
|
||||
Common operations can be performed the same way:
|
||||
|
||||
```thp
|
||||
val value1 = 552.23 - 32
|
||||
val value2 = 3.2 * (-0.22 + 23.334) / 0.5
|
||||
// etc.
|
||||
```
|
||||
|
||||
### String
|
||||
|
||||
A string of letters (technically, characters). Strings are used to represent text,
|
||||
and are wrapped in quotation marks.
|
||||
|
||||
```thp
|
||||
val name = "John"
|
||||
val lastName = "Doe"
|
||||
|
||||
val greeting = "Hello"
|
||||
```
|
||||
|
||||
#### Concatenation
|
||||
|
||||
Strings cannot be added, substracted, multiplied, divided.
|
||||
They have another operation, called "concatenation".
|
||||
|
||||
Concatenation "joins" two strings, for example, the concatenation of
|
||||
`"human"` and `"kind"` is `"humankind"`.
|
||||
|
||||
As it is a common operation, string concatenation reuses the operation
|
||||
for addition `+`.
|
||||
|
||||
```thp
|
||||
val string = "human" + "kind"
|
||||
```
|
||||
|
||||
|
||||
### Boolean
|
||||
|
||||
A boolean represents something that can only be in one of two states.
|
||||
|
||||
Booleans are useful in conditionals, which will be explained later.
|
||||
|
||||
|
||||
```thp
|
||||
val condition = true
|
||||
val isSunny = false
|
||||
|
||||
if isSunny {
|
||||
doSomething()
|
||||
}
|
||||
```
|
||||
|
||||
|
60
md/learn/basics/hello-world.md
Normal file
60
md/learn/basics/hello-world.md
Normal file
@ -0,0 +1,60 @@
|
||||
# Hello, world!
|
||||
|
||||
This pages shows you how to write and run your first THP script.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You will need to have PHP and THP installed. If you haven't already, see the
|
||||
install page.
|
||||
|
||||
## Writing the program
|
||||
|
||||
Create a new file called `hello.thp`, and inside write the following (you can
|
||||
copy and paste):
|
||||
|
||||
```thp
|
||||
print("Hello, world!")
|
||||
```
|
||||
|
||||
Then, save the code.
|
||||
|
||||
## Running the program
|
||||
|
||||
Open a terminal in the folder where you created the file `hello.thp`.
|
||||
Then write the following command and press enter:
|
||||
|
||||
```sh
|
||||
thp hello.thp
|
||||
```
|
||||
|
||||
This will run the program, and produce the following result:
|
||||
|
||||
```sh
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
Congratulations! You just wrote your first THP program!
|
||||
|
||||
## Explaining the program
|
||||
|
||||
Now let's understand the code.
|
||||
|
||||
```thp
|
||||
print("Hello, world!")
|
||||
```
|
||||
|
||||
There are 2 essential components:
|
||||
|
||||
- `print` - print is a "function", it takes some value and performs some action with it.
|
||||
In this case, it takes a text and displays it in the terminal.
|
||||
- `"Hello, world!"` - Is the text that the function `print` takes, and displays in
|
||||
the terminal. Note that it is enclosed in quotation marks.
|
||||
|
||||
## What to do next
|
||||
|
||||
You can now experiment with the program you wrote. What happens if you change the text?
|
||||
What if you don't put quotation marks? And what are the parenthesis for?
|
||||
|
||||
To continue learning about THP, continue to the next page, where you'll learn
|
||||
about "datatypes".
|
||||
|
64
md/learn/basics/io.md
Normal file
64
md/learn/basics/io.md
Normal file
@ -0,0 +1,64 @@
|
||||
# Input & Output
|
||||
|
||||
At the end of the day, a program takes some input,
|
||||
and transform it to some output. We will explore how to
|
||||
receive data, and also present it.
|
||||
|
||||
## Output
|
||||
|
||||
There are many ways to show the result of our programs.
|
||||
One of them is called `standard output`, which in simplified
|
||||
terms, is the terminal from where we run our program.
|
||||
|
||||
### `print`
|
||||
|
||||
Create an empty file, and name it `hello.php`. We will create
|
||||
a program that shows a result to our screen.
|
||||
|
||||
Inside `hello.php` write the following code:
|
||||
|
||||
```thp
|
||||
print("Hello")
|
||||
```
|
||||
|
||||
Then, open a terminal and run the program with the `thp` command.
|
||||
After you press ENTER, you will see in the terminal the text "Hello".
|
||||
|
||||
|
||||
```sh
|
||||
$ thp hello.thp # Copy this command and run it
|
||||
Hello # This is the output of our program
|
||||
```
|
||||
|
||||
The thp function `print` allows us to display something in the terminal.
|
||||
|
||||
If you change the `hello.php` file, and run it, you'll see how it changes.
|
||||
|
||||
```thp
|
||||
print(322)
|
||||
```
|
||||
```sh
|
||||
$ thp hello.php
|
||||
322
|
||||
```
|
||||
|
||||
Or, if you copy `print` multiple times, each will show something in the screen.
|
||||
|
||||
```thp
|
||||
print("Hello")
|
||||
print("This is an example")
|
||||
print("of having many prints")
|
||||
```
|
||||
```sh
|
||||
$ thp hello.php
|
||||
Hello
|
||||
This is an example
|
||||
of having many prints
|
||||
```
|
||||
|
||||
### Using `print` in a larger program
|
||||
|
||||
|
||||
|
||||
|
||||
|
5
md/learn/basics/operators.md
Normal file
5
md/learn/basics/operators.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Operators
|
||||
|
||||
Some common operators
|
||||
|
||||
|
72
md/learn/basics/the-compiler.md
Normal file
72
md/learn/basics/the-compiler.md
Normal file
@ -0,0 +1,72 @@
|
||||
# The compiler
|
||||
|
||||
The compiler is the program that takes your THP code and converts it
|
||||
into something that the computer can run (in this case, PHP code).
|
||||
|
||||
|
||||
|
||||
The compiler reads your code and tries to understand it.
|
||||
When it can't understand some part, it will ask you to clarify what
|
||||
you meant, with an error.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Compile time vs runtime
|
||||
|
||||
Compile time is when you build your program.
|
||||
|
||||
Runtime is when you run your program.
|
||||
|
||||
To make an analogy with cars, compile time would be the factory,
|
||||
while runtime would be using the finished car.
|
||||
|
||||
|
||||
|
||||
The compiler is very strict. If it finds any errors during compile time
|
||||
it will refuse to build the program.
|
||||
|
||||
|
||||
### Compile time errors
|
||||
|
||||
Compile time errors are errors that happen while the compiler is
|
||||
building your program. In the car analogy, a compile error would happen
|
||||
if there's an error in the "blueprint"
|
||||
|
||||
|
||||
### Runtime errors
|
||||
|
||||
These are errors that happen to the built program, or in this case,
|
||||
the finished car. It would be like the car blowing up while on the highway.
|
||||
|
||||
To minimize the amount of runtime errors the compiler tries to catch them all
|
||||
during compile time. It's better if it fails in the factory than in the
|
||||
real world.
|
||||
|
||||
|
||||
## The compiler and datatypes
|
||||
|
||||
The first measure the compiler takes is to check that all the datatypes
|
||||
match. If an operation requires a number, you can't just give it a string.
|
||||
|
||||
|
||||
|
||||
For example, if we wanted to add a number to a string, we would get an
|
||||
error:
|
||||
|
||||
```thp
|
||||
50 + "hello" // Error: The `+` operator expects two Numbers,
|
||||
// but an String was found.
|
||||
```
|
||||
|
||||
This way, we can assure that many errors are avoided (since it doesn't
|
||||
really make sense to add a number to a text).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
139
md/learn/basics/variables.md
Normal file
139
md/learn/basics/variables.md
Normal file
@ -0,0 +1,139 @@
|
||||
# Variables
|
||||
|
||||
Variables allows us to store values under a name, so that we can use them
|
||||
later.
|
||||
|
||||
For example, in a program we could have the name of our user, and use it
|
||||
multiple times:
|
||||
|
||||
```thp
|
||||
print("Hello, where's Joe?")
|
||||
print("How old is Joe?")
|
||||
print("Do you know if Joe has kids?")
|
||||
```
|
||||
|
||||
We are using the same value `Joe` many times. Each time we use it we have
|
||||
to type `Joe`. But what happens if we needed to use a different name?
|
||||
We'd have to change the name everywhere in our code!
|
||||
|
||||
```thp
|
||||
print("Hello, where's Jane?")
|
||||
print("How old is Jane?")
|
||||
print("Do you know if Jane has kids?")
|
||||
```
|
||||
|
||||
## Variables to the rescue
|
||||
|
||||
With a variable we can store values so we can use them later, or use them
|
||||
in multiple times.
|
||||
|
||||
In the previous code, we can use a variable to store the person's name,
|
||||
and then use it everywhere.
|
||||
|
||||
```thp
|
||||
// This is the variable
|
||||
val person = "John"
|
||||
|
||||
print("Hello, where's {person}?")
|
||||
print("How old is {person}?")
|
||||
print("Do you know if Joe has {person}?")
|
||||
```
|
||||
|
||||
Now, instead of writing `"John"` every time, we write the name of the
|
||||
variable instead.
|
||||
|
||||
If we wanted to change the person's name to "Jane", we just need to change
|
||||
it in one place: the variable
|
||||
|
||||
```thp
|
||||
// We change this
|
||||
val person = "Jane"
|
||||
|
||||
// And all these lines will use the new value
|
||||
print("Hello, where's {person}?")
|
||||
print("How old is {person}?")
|
||||
print("Do you know if Joe has {person}?")
|
||||
```
|
||||
|
||||
## Variable rules
|
||||
|
||||
To use a variable we do the following:
|
||||
|
||||
- Write the special word `val`
|
||||
- Write the name of our variable
|
||||
- Write the equal sign `=`
|
||||
- Write the value of our variable
|
||||
|
||||
```thp
|
||||
val person = "Jane"
|
||||
/* --- ------ - ------
|
||||
| | | +- The value of our variable
|
||||
| | +----- The equal sign
|
||||
| +---------- The name of our variable
|
||||
+--------------- The special word (keyword) val
|
||||
*/
|
||||
```
|
||||
|
||||
The value can be anything: ints, floats, string, bools, even other variables and operations!
|
||||
|
||||
```thp
|
||||
val variable_1 = 322
|
||||
val variable_2 = 123.456
|
||||
val variable_3 = "a text"
|
||||
val variable_4 = false
|
||||
val variable_5 = variable_1 + variable 2
|
||||
```
|
||||
|
||||
## Variable name rules
|
||||
|
||||
- Starts with a lowercase letter (a-z) or underscore (`_`)
|
||||
- Then can have any letter (a-zA-Z), underscore (`_`) or number (0-9)
|
||||
- Cannot have spaces
|
||||
- Cannot have the same name as a keyword (for example, the `val` keyword)
|
||||
|
||||
|
||||
Some examples of valid variable names:
|
||||
|
||||
```thp
|
||||
val name = ...
|
||||
val age = ...
|
||||
val my_name = ...
|
||||
val many_words_joined_by_underscores = ...
|
||||
val person_2 = ...
|
||||
val person_3 = ...
|
||||
```
|
||||
|
||||
Some invalid variables and why they are invalid:
|
||||
|
||||
```thp
|
||||
val 1name = ... // Invalid: starts with a number
|
||||
val 123_person = ... // Invalid: starts with a number
|
||||
val val = ... // Invalid: same name as a keyword (val)
|
||||
val Person = ... // Invalid: starts with an uppercase letter
|
||||
val person name = ... // Invalid: contains whitespace
|
||||
val +@name = ... // Invalid: contains non-letters (+@)
|
||||
val name🫠 = ... // Invalid: contains emoji (🫠)
|
||||
```
|
||||
|
||||
|
||||
## Variable reassignment
|
||||
|
||||
When you create a new variable with the same name of an old variable,
|
||||
the old is "replaced" with the new one.
|
||||
|
||||
```thp
|
||||
val person_name = "John"
|
||||
print(person_name) // Will print "John"
|
||||
|
||||
val person_name = "Jane"
|
||||
print(person_name) // Will print "Jane"
|
||||
```
|
||||
|
||||
This will have some implications on the future, but for now you should
|
||||
now that you will always use the value of the last variable you define.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
0
md/learn/flow-control/break-continue.md
Normal file
0
md/learn/flow-control/break-continue.md
Normal file
3
md/learn/flow-control/conditionals.md
Normal file
3
md/learn/flow-control/conditionals.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Conditionals
|
||||
|
||||
|
0
md/learn/flow-control/foreach.md
Normal file
0
md/learn/flow-control/foreach.md
Normal file
0
md/learn/flow-control/if-expresions.md
Normal file
0
md/learn/flow-control/if-expresions.md
Normal file
0
md/learn/flow-control/match.md
Normal file
0
md/learn/flow-control/match.md
Normal file
0
md/learn/flow-control/while.md
Normal file
0
md/learn/flow-control/while.md
Normal file
71
md/learn/functions/parameters.md
Normal file
71
md/learn/functions/parameters.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Function parameters
|
||||
|
||||
|
||||
## Immutable reference
|
||||
|
||||
```thp
|
||||
fun add_25(Array[Int] numbers) {
|
||||
numbers.push(25) // Error: `numbers` is immutable
|
||||
}
|
||||
```
|
||||
|
||||
When using a regular type as a parameter, only it's immutable
|
||||
properties can be used inside the function
|
||||
|
||||
```thp
|
||||
fun count(Array[Int] numbers) -> Int {
|
||||
val items_count = numbers.size() // Ok, `size` is pure
|
||||
|
||||
items_count
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Mutable reference
|
||||
|
||||
```thp
|
||||
fun add_25(&Array[Int] numbers) {
|
||||
numbers.push(25) // Ok, will also mutate the original array
|
||||
}
|
||||
```
|
||||
|
||||
Placing a `&` before the type makes the parameter a mutable
|
||||
reference. Mutable methods can be used, and the original
|
||||
data **will** be mutated.
|
||||
|
||||
The callee *must* also use `&`.
|
||||
|
||||
```thp
|
||||
val numbers = Array(1, 2, 3, 4)
|
||||
|
||||
add_25(&numbers) // Pass `numbers` as reference.
|
||||
|
||||
print(numbers(4)) // `Some(25)`
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Clone
|
||||
|
||||
```thp
|
||||
fun add_25(clone Array[Int] numbers) {
|
||||
numbers.push(25) // Ok, the original array is unaffected
|
||||
}
|
||||
```
|
||||
|
||||
Using the `clone` keyword before the type creates a mutable copy
|
||||
of the parameter. The original data will **not** be mutated.
|
||||
|
||||
|
||||
```thp
|
||||
val numbers = Array(1, 2, 3, 4)
|
||||
|
||||
add_25(&numbers) // Pass `numbers` as reference.
|
||||
|
||||
print(numbers(4)) // None
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
201
md/learn/ideas/idea_1.md
Normal file
201
md/learn/ideas/idea_1.md
Normal file
@ -0,0 +1,201 @@
|
||||
# Idea 1
|
||||
|
||||
|
||||
var x = 20
|
||||
val y = 30
|
||||
|
||||
type Something = ...
|
||||
|
||||
Something s1 = ...
|
||||
Something s2 = s1
|
||||
|
||||
|
||||
// Passes `some` by reference, but it's immutable. Cannot call mutable methods
|
||||
// or use it in mutable operations
|
||||
fun do_something(Something some) -> Bool {}
|
||||
do_something(s1)
|
||||
|
||||
// Passes `some` by reference, and it's mutable. Can call mutable methods
|
||||
// or use it in mutable operations
|
||||
fun do_something(&Something some) -> Bool {}
|
||||
do_something(&s1)
|
||||
|
||||
|
||||
var arr1 = Array(10, 20, 30)
|
||||
var arr2 = &arr1
|
||||
|
||||
|
||||
Owned/Reference Mutable
|
||||
Type Owned n
|
||||
&Type Reference n
|
||||
mut Type Owned y
|
||||
&mut Type Reference y
|
||||
|
||||
|
||||
Copy/Reference Mutable Equivalent
|
||||
Some Copy n 1 (technically) references the other data
|
||||
&Some Reference n 1 References the other data
|
||||
mut Some Copy y 2 Creates a __mutable__ copy
|
||||
&mut Some Reference y 3 References the other data, __mutable__
|
||||
|
||||
|
||||
## `Array[A]::map`
|
||||
|
||||
```thp
|
||||
fun map[B](this, (A) -> B callback) -> Array[B]
|
||||
```
|
||||
|
||||
Applies `callback` to all the elements of this array, and
|
||||
returns those new values in a new array.
|
||||
|
||||
### Example
|
||||
|
||||
```thp
|
||||
val numbers = Array(1, 2, 3, 4, 5)
|
||||
|
||||
val numbers_squared = numbers.map {it ** 2}
|
||||
|
||||
print(numbers_squared) // Array(1, 4, 9, 16, 25)
|
||||
|
||||
numbers.map(fun(v) {
|
||||
v - 2
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
## `Array[A]::reduce`
|
||||
|
||||
```thp
|
||||
fun reduce[B](
|
||||
this,
|
||||
B initial,
|
||||
(A previous, B current) -> B callback,
|
||||
) -> B
|
||||
```
|
||||
|
||||
Iteratively reduce the array to a single value using `callback`.
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
```thp
|
||||
val numbers = Array(1, 2, 3, 4, 5)
|
||||
|
||||
val sum = numbers.reduce(0, \+)
|
||||
val sum = numbers.reduce(0) {$1 + $2}
|
||||
val sum = numbers.reduce(0, fun(prev, curr) {prev + curr})
|
||||
|
||||
print(sum) // 15
|
||||
```
|
||||
|
||||
|
||||
```thp
|
||||
val numbers = Array(1, 2, 3, 4, 5)
|
||||
|
||||
val sum = numbers.reduce("", fun(prev, curr) {prev + curr})
|
||||
|
||||
val sum = numbers.reduce("") {prev, curr -> prev + curr}
|
||||
|
||||
print(sum) // "12345"
|
||||
```
|
||||
|
||||
|
||||
```thp
|
||||
// Functor
|
||||
|
||||
fun fmap(
|
||||
(A) -> B,
|
||||
f[A],
|
||||
) -> f[B]
|
||||
|
||||
fun (<$)(
|
||||
A,
|
||||
f[B],
|
||||
) -> f[A]
|
||||
|
||||
|
||||
// Applicative
|
||||
|
||||
fun pure(A) -> f[A]
|
||||
|
||||
fun (<*>)(
|
||||
f[A -> B],
|
||||
f[A],
|
||||
) -> f[B]
|
||||
|
||||
fun (*>)(
|
||||
f[_],
|
||||
f[B],
|
||||
) -> f[B]
|
||||
|
||||
fun (<*)(
|
||||
f[A],
|
||||
f[_],
|
||||
) -> f[A]
|
||||
|
||||
|
||||
// Monad
|
||||
|
||||
fun (>>=)[m, A, B](
|
||||
m[A],
|
||||
(A) -> m[B],
|
||||
) -> m[B]
|
||||
|
||||
|
||||
(Array[Int], Int -> Array[String]) -> Array[String]
|
||||
|
||||
val result = Array(1, 2, 3, 4, 5) >>= {Array($.into[String]())}
|
||||
|
||||
print(result) // Array("1", "2", "3", "4", "5")
|
||||
```
|
||||
|
||||
|
||||
```thp
|
||||
Option[Int] result = "322".try_into()
|
||||
Option[Int] result_halved = result >>= {Some($ / 2)}
|
||||
|
||||
print(result_halved) // Some(161)
|
||||
|
||||
|
||||
Option[Int] result = "abc".try_into()
|
||||
Option[Int] result_halved = result >>= {Some($ / 2)}
|
||||
|
||||
print(result_halved) // None
|
||||
```
|
||||
|
||||
```thp
|
||||
fun (<$>)[m, A, B](
|
||||
(A) -> B,
|
||||
m[A],
|
||||
) -> m[B]
|
||||
|
||||
|
||||
fun half(Int x) -> Int {
|
||||
x / 2
|
||||
}
|
||||
|
||||
|
||||
Option[Int] result = "322".try_into()
|
||||
Option[Int] result_halved = result <$> half
|
||||
|
||||
print(result_halved) // Some(161)
|
||||
|
||||
|
||||
Option[Int] result = "abc".try_into()
|
||||
Option[Int] result_halved = result <$> half
|
||||
|
||||
print(result_halved) // None
|
||||
```
|
||||
|
||||
```thp
|
||||
fun (>>)[A, B, C](
|
||||
(A) -> B,
|
||||
(B) -> C,
|
||||
) -> (A) -> C
|
||||
|
||||
val f1 = add1 >> times2
|
||||
|
||||
f1(5) // 12
|
||||
```
|
||||
|
@ -4,6 +4,13 @@ Welcome to the documentation of the THP programming languague.
|
||||
|
||||
THP is a new programming language that compiles to PHP.
|
||||
|
||||
<br>
|
||||
|
||||
This page discusses some of the design decitions of the language,
|
||||
if you want to install THP go to the installation guide](/installation-guide)
|
||||
|
||||
If you want to learn the language, go to the learn section.
|
||||
|
||||
## Goals
|
||||
|
||||
- Bring static typing to PHP: Not just type hints, not use `mixed` for everything
|
||||
|
@ -4,3 +4,25 @@ has_index: true
|
||||
children:
|
||||
- path: index
|
||||
name: Index
|
||||
- path: install
|
||||
name: Install
|
||||
- path: basics
|
||||
name: Basics
|
||||
children:
|
||||
- path: hello-world
|
||||
name: Hello, world!
|
||||
- path: datatypes
|
||||
name: Datatypes
|
||||
- path: the-compiler
|
||||
name: The compiler
|
||||
- name: Variables
|
||||
path: variables
|
||||
- path: io
|
||||
name: Input & Output
|
||||
- path: comments
|
||||
name: Comments
|
||||
- name: Flow control
|
||||
path: flow-control
|
||||
children:
|
||||
- name: Conditionals
|
||||
path: conditionals
|
||||
|
10
md/learn/install.md
Normal file
10
md/learn/install.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Install
|
||||
|
||||
## From scratch
|
||||
|
||||
Also install php (through XAMPP in windows/mac, php in linux) and Composer.
|
||||
|
||||
## With composer
|
||||
|
||||
TBD, the user should be able to just run `composer require thp` and
|
||||
the proper binary should be intalled.
|
403
pnpm-lock.yaml
403
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -12,157 +12,71 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:wght@400;500;600;700;800;900&family=Fugaz+One&family=Inconsolata&family=Inter&display=swap" rel="stylesheet">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Code&family=Josefin+Sans:ital,wght@0,400;1,700&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-c-bg text-c-text">
|
||||
<div class="px-2 grid grid-cols-2 gap-4 relative">
|
||||
<div class="text-center h-screen overflow-hidden sticky top-0 left-0">
|
||||
|
||||
<div class="rounded-md m-4 p-4 bg-c-primary"
|
||||
style="box-shadow: 0 0 10px -4px var(--c-box-shadow);"
|
||||
>
|
||||
<h1
|
||||
class="py-8 font-display"
|
||||
style="font-size: 10rem; text-shadow: 3px 3px 0 var(--c-bg)"
|
||||
>
|
||||
thp 23
|
||||
</h1>
|
||||
<h1 class="text-6xl text-center py-8 font-display"
|
||||
style="text-shadow: 1px 1px 0 var(--c-bg)"
|
||||
>
|
||||
Typed Hypertext Processor
|
||||
</h1>
|
||||
|
||||
<p class="text-2xl">
|
||||
A <b>modern, consistent</b> typed language for PHP.
|
||||
</p>
|
||||
|
||||
<div class="m-4 relative mb-2 button-effect inline-block bg-c-bg rounded">
|
||||
<button class="button-effect-receiver py-2 px-4 rounded font-display
|
||||
bg-c-text text-c-primary"
|
||||
>
|
||||
Get started
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="m-4 relative mb-2 button-effect inline-block bg-c-bg rounded">
|
||||
<a class="button-effect-receiver py-2 px-4 rounded font-display inline-block
|
||||
bg-c-text text-c-primary"
|
||||
href="/learn/"
|
||||
>
|
||||
Learn
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="max-w-[70rem] mx-auto py-28 grid grid-cols-2 gap-4"
|
||||
>
|
||||
<div>
|
||||
<h1 class="font-display font-bold italic text-[6rem] leading-tight">
|
||||
Typed
|
||||
<br>
|
||||
Hypertext
|
||||
<br>
|
||||
Processor
|
||||
</h1>
|
||||
<p class="font-display text-3xl pt-4">
|
||||
Syntax, stdlib and types for PHP
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="rounded-md my-4 mx-2 p-4 bg-c-primary"
|
||||
style="box-shadow: 0 0 10px -4px var(--c-box-shadow);"
|
||||
<div
|
||||
class="bg-[var(--code-theme-bg-color)] p-8 rounded-lg"
|
||||
>
|
||||
<h2 class="text-2xl mb-2">
|
||||
A truly Static Type System
|
||||
</h2>
|
||||
<p>
|
||||
thp keeps track of the datatype of all variables, and allows
|
||||
you to have complex types and type inference.
|
||||
</p>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg>
|
||||
<br>
|
||||
<pre
|
||||
class="p-2 my-2 rounded-md bg-c-bg language-misti"
|
||||
style="box-shadow: inset 0 0 10px -5px var(--c-box-shadow);"
|
||||
>type <span class="token class-name">Person</span> = {
|
||||
<span class="token class-name">String</span> name,
|
||||
<span class="token class-name">String</span> lastName,
|
||||
<span class="token class-name">Int</span> age,
|
||||
class="rounded-md bg-c-bg language-misti"
|
||||
style="padding: 0 !important;"
|
||||
><span class="token keyword">use</span> <span class="token class-name">Globals</span>::<span class="token class-name">POST</span>
|
||||
<span class="token keyword">use</span> <span class="token class-name">JSON</span>
|
||||
|
||||
<span class="token keyword">val</span> person_id = <span class="token class-name">POST</span>::get(<span class="token string">"person_id"</span>) ?: <span class="token keyword">die</span>
|
||||
|
||||
<span class="token keyword">match</span> <span class="token class-name">Person</span>::find_by_id(person_id) {
|
||||
<span class="token class-name">Ok</span>(person) => {
|
||||
<span class="token class-name">JSON</span>::encode(person)
|
||||
}
|
||||
<span class="token class-name">Err</span>(e) => {
|
||||
<span class="token class-name">JSON</span>::encode(Obj {<span class="token string">"error"</span>: e})
|
||||
}
|
||||
}
|
||||
|
||||
<span class="token class-name">Option</span>[<span class="token class-name">Array</span>[<span class="token class-name">Person</span>]] persons = <span class="token class-name">PersonManager</span>::getAll()
|
||||
|
||||
print(<span class="token string">"There are {persons?.length ?? 0} persons registered!"</span>)</pre>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="rounded-md my-4 mx-2 p-4 bg-c-primary"
|
||||
style="box-shadow: 0 0 10px -4px var(--c-box-shadow);"
|
||||
>
|
||||
<h2 class="text-2xl mb-2">
|
||||
A <b>new</b> stdlib for PHP
|
||||
</h2>
|
||||
<p>
|
||||
thp groups all global variables and function of PHP into modules,
|
||||
to allow easy access and organization.
|
||||
<br>
|
||||
Function names, parameters and return types are improved, and you
|
||||
can treat primitive types as objects.
|
||||
</p>
|
||||
|
||||
<pre
|
||||
class="p-2 my-2 rounded-md bg-c-bg language-misti"
|
||||
style="box-shadow: inset 0 0 10px -5px var(--c-box-shadow);"
|
||||
><span class="token keyword">val</span> name = <span class="token string">"John Doe"</span>
|
||||
|
||||
<span class="token keyword">val</span> lastNamePos = name.indexOf(<span class="token string">"Doe"</span>) <span class="token comment">// Instead of `strpos`</span>
|
||||
<span class="token keyword">val</span> letters = name.split(<span class="token string">""</span>) <span class="token comment">// Instead of `str_split` or `explode`</span>
|
||||
|
||||
<span class="token keyword">val</span> notALetters = letters.filter { $ != <span class="token string">"a"</span> } <span class="token comment">// Instead of `array_filter`</span></pre>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="rounded-md my-4 mx-2 p-4 bg-c-primary"
|
||||
style="box-shadow: 0 0 10px -4px var(--c-box-shadow);"
|
||||
>
|
||||
<h2 class="text-2xl mb-2">
|
||||
Sound null safety & Pattern Matching
|
||||
</h2>
|
||||
<p>
|
||||
All null values must be explicitly marked and handled,
|
||||
avoiding many errors, via the <code>Option</code> ADT.
|
||||
<br>
|
||||
<br>
|
||||
Also, functions that return <code>false</code> as
|
||||
an error state now return an <code>Option</code>,
|
||||
and exceptions return a <code>Result</code> instead.
|
||||
</p>
|
||||
|
||||
<pre
|
||||
class="p-2 my-2 rounded-md bg-c-bg language-misti"
|
||||
style="box-shadow: inset 0 0 10px -5px var(--c-box-shadow);"
|
||||
><span class="token keyword">val</span> allowedColors = <span class="token class-name">Array</span>(<span class="token string">"red"</span>, <span class="token string">"blue"</span>, <span class="token string">"green"</span>)
|
||||
|
||||
<span class="token keyword">val</span> response = match colors.search(<span class="token string">"purple"</span>) {
|
||||
<span class="token class-name">Some</span>(_) -> <span class="token string">"purple is allowed!"</span>
|
||||
<span class="token class-name">None</span> -> <span class="token string">"purple is not allowed"</span>
|
||||
}
|
||||
|
||||
print(response)</pre>
|
||||
|
||||
<pre
|
||||
class="p-2 my-2 rounded-md bg-c-bg language-misti"
|
||||
style="box-shadow: inset 0 0 10px -5px var(--c-box-shadow);"
|
||||
>use <span class="token class-name">PDO</span>
|
||||
use <span class="token class-name">Globals</span>::<span class="token class-name">Env</span>
|
||||
|
||||
<span class="token keyword">val</span> #(<span class="token class-name">Some</span>(dbUri), <span class="token class-name">Some</span>(dbUser), <span class="token class-name">Some</span>(dbPassword)) = #(
|
||||
<span class="token class-name">Env</span>::get(<span class="token string">"DB_URI"</span>),
|
||||
<span class="token class-name">Env</span>::get(<span class="token string">"DB_USERNAME"</span>),
|
||||
<span class="token class-name">Env</span>::get(<span class="token string">"DB_PASSWORD"</span>),
|
||||
)
|
||||
else {
|
||||
die(<span class="token string">"All 3 db environment variables must be set."</span>)
|
||||
}
|
||||
|
||||
match <span class="token class-name">PDO</span>(dbUri, dbUser, dbPassword) {
|
||||
<span class="token class-name">Ok</span>(connection) -> { /* db operations */ }
|
||||
<span class="token class-name">Err</span>(pdoException) -> { /* handle exception */ }
|
||||
}</pre>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="max-w-[70rem] mx-auto text-center"
|
||||
>
|
||||
<a
|
||||
class="inline-block font-display text-2xl border-4 border-[#F5A9B8] py-3 px-8 mx-6 rounded"
|
||||
href="/learn/"
|
||||
>
|
||||
Learn
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="inline-block font-display text-2xl border-4 border-[#5BCEFA] py-3 px-8 mx-6 rounded"
|
||||
href="/install/"
|
||||
>
|
||||
Install
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -13,16 +13,23 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:wght@400;500;600;700;800;900&family=Fugaz+One&family=Inconsolata&family=Inter&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Code&family=Josefin+Sans:ital,wght@0,400;1,700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
html {
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-c-bg text-c-text">
|
||||
<div class="grid grid-cols-[10rem_12rem_auto] gap-2">
|
||||
<div class="grid grid-cols-[10rem_12rem_auto] gap-2 max-w-[70rem] mx-auto">
|
||||
<div class="p-2 overflow-x-scroll max-h-screen sticky top-0">
|
||||
<div class="relative mb-2 button-effect">
|
||||
<a class="button-effect-receiver inline-block w-[9rem] p-4 bg-c-primary rounded-md"
|
||||
href="/"
|
||||
>
|
||||
<h1
|
||||
class="py-8 font-display text-6xl text-center"
|
||||
class="py-8 font-display text-6xl text-center font-bold italic"
|
||||
style="text-shadow: 3px 3px 0 var(--c-bg)"
|
||||
>
|
||||
thp
|
||||
@ -32,13 +39,13 @@
|
||||
<div class="w-full h-full bg-c-text absolute top-0 left-0 -z-10 rounded-md"></div>
|
||||
</div>
|
||||
|
||||
<nav class="rounded-md p-4 bg-c-primary">
|
||||
<nav class="rounded-md p-4 border-2 border-[#F5A9B8]">
|
||||
{{pages}}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="py-2 max-h-screen overflow-x-scroll sticky top-0">
|
||||
<nav class="rounded-md p-4 bg-c-secondary">
|
||||
<nav class="rounded-md p-4 border-2 border-[#5BCEFA]">
|
||||
<h2 class="text-2xl">On this page</h2>
|
||||
|
||||
<br>
|
||||
@ -46,7 +53,7 @@
|
||||
{{sidebar}}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
<main class="markdown p-4 my-2">
|
||||
{{markdown}}
|
||||
</main>
|
||||
|
@ -16,9 +16,10 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
fontFamily: {
|
||||
"mono": ["Inconsolata", "Iosevka", "monospace"],
|
||||
"display": ["'Fugaz One'", "Inter", "'Fira Sans Condensed'", "sans-serif"],
|
||||
"mono": ["'Fira Code'", "Inconsolata", "Iosevka", "monospace"],
|
||||
"display": ["'Josefin Sans'", "'Fugaz One'", "sans-serif"],
|
||||
"body": ["'Fira Sans Condensed'", "Inter", "sans-serif"],
|
||||
"nav-title": ["'Josefin Sans'", "'Fugaz One'", "sans-serif"],
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
|
@ -33,7 +33,7 @@ body {
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-family: Inconsolata, monospace;
|
||||
font-family: 'Fira Code', Inconsolata, monospace;
|
||||
}
|
||||
|
||||
.button-effect-receiver {
|
||||
@ -44,6 +44,9 @@ pre, code {
|
||||
transform: translateX(-3px) translateY(-3px);
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 0.75rem 0;
|
||||
}
|
||||
|
||||
/* Used by headers generated from markdown */
|
||||
.heading-linked :hover::after{
|
||||
|
Loading…
Reference in New Issue
Block a user