2023-12-14 18:12:25 +03:00
|
|
|
---
|
2024-10-21 00:46:35 +03:00
|
|
|
language: Arturo
|
2023-12-14 18:12:25 +03:00
|
|
|
filename: learnarturo.art
|
|
|
|
contributors:
|
|
|
|
- ["Dr.Kameleon", "https://github.com/drkameleon"]
|
|
|
|
---
|
|
|
|
|
|
|
|
```red
|
|
|
|
; this is a comment
|
|
|
|
; this is another comment
|
|
|
|
|
|
|
|
;---------------------------------
|
|
|
|
; VARIABLES & VALUES
|
|
|
|
;---------------------------------
|
|
|
|
|
|
|
|
; numbers
|
|
|
|
a1: 2
|
|
|
|
a2: 3.14
|
|
|
|
a3: to :complex [1 2.0] ; 1.0+2.0i
|
|
|
|
|
|
|
|
; strings
|
|
|
|
c1: "this is a string"
|
|
|
|
c2: {
|
|
|
|
this is a multiline string
|
|
|
|
that is indentation-agnostic
|
|
|
|
}
|
|
|
|
c3: {:
|
|
|
|
this is
|
|
|
|
a verbatim
|
|
|
|
multiline string
|
|
|
|
which will remain exactly
|
|
|
|
as the original
|
|
|
|
:}
|
|
|
|
|
|
|
|
; characters
|
|
|
|
ch: `c`
|
|
|
|
|
|
|
|
; blocks/arrays
|
|
|
|
d: [1 2 3]
|
|
|
|
|
|
|
|
; dictionaries
|
|
|
|
e: #[
|
|
|
|
name: "John"
|
|
|
|
surname: "Doe"
|
|
|
|
age: 34
|
|
|
|
likes: [pizza spaghetti]
|
|
|
|
]
|
|
|
|
|
|
|
|
; yes, functions are values too
|
|
|
|
f: function [x][
|
|
|
|
2 * x
|
|
|
|
]
|
|
|
|
|
|
|
|
; dates
|
|
|
|
g: now ; 2021-05-03T17:10:48+02:00
|
|
|
|
|
|
|
|
; booleans
|
|
|
|
h1: true
|
|
|
|
h2: false
|
|
|
|
|
|
|
|
;---------------------------------
|
|
|
|
; BASIC OPERATORS
|
|
|
|
;---------------------------------
|
|
|
|
|
|
|
|
; simple arithmetic
|
|
|
|
1 + 1 ; => 2
|
|
|
|
8 - 1 ; => 7
|
|
|
|
4.2 - 1.1 ; => 3.1
|
|
|
|
10 * 2 ; => 20
|
|
|
|
35 / 4 ; => 8
|
|
|
|
35 // 4 ; => 8.75
|
|
|
|
2 ^ 5 ; => 32
|
|
|
|
5 % 3 ; => 2
|
|
|
|
|
|
|
|
; bitwise operators
|
|
|
|
and 3 5 ; => 1
|
|
|
|
or 3 5 ; => 7
|
|
|
|
xor 3 5 ; => 6
|
|
|
|
|
|
|
|
; pre-defined constants
|
|
|
|
pi ; => 3.141592653589793
|
|
|
|
epsilon ; => 2.718281828459045
|
|
|
|
null ; => null
|
|
|
|
true ; => true
|
|
|
|
false ; => false
|
|
|
|
|
|
|
|
;---------------------------------
|
|
|
|
; COMPARISON OPERATORS
|
|
|
|
;---------------------------------
|
|
|
|
|
|
|
|
; equality
|
|
|
|
1 = 1 ; => true
|
|
|
|
2 = 1 ; => false
|
|
|
|
|
|
|
|
; inequality
|
|
|
|
1 <> 1 ; => false
|
|
|
|
2 <> 1 ; => true
|
|
|
|
|
|
|
|
; more comparisons
|
|
|
|
1 < 10 ; => true
|
|
|
|
1 =< 10 ; => true
|
|
|
|
10 =< 10 ; => true
|
|
|
|
1 > 10 ; => false
|
|
|
|
1 >= 10 ; => false
|
|
|
|
11 >= 10 ; => true
|
|
|
|
|
|
|
|
;---------------------------------
|
|
|
|
; CONDITIONALS
|
|
|
|
;---------------------------------
|
|
|
|
|
|
|
|
; logical operators
|
|
|
|
and? true true ; => true
|
|
|
|
and? true false ; => false
|
|
|
|
or? true false ; => true
|
|
|
|
or? false false ; => false
|
|
|
|
|
|
|
|
and? [1=2][2<3] ; => false
|
|
|
|
; (the second block will not be evaluated)
|
|
|
|
|
|
|
|
; simple if statements
|
|
|
|
if 2 > 1 [ print "yes!"] ; yes!
|
|
|
|
if 3 <> 2 -> print "true!" ; true!
|
|
|
|
|
|
|
|
; if/else statements
|
|
|
|
if? 2 > 3 -> print "2 is greater than 3"
|
|
|
|
else -> print "2 is not greater than 3" ; 2 is not greater than 3
|
|
|
|
|
|
|
|
; switch statements
|
|
|
|
switch 2 > 3 -> print "2 is greater than 3"
|
|
|
|
-> print "2 is not greater than 3" ; 2 is not greater than 3
|
|
|
|
|
|
|
|
a: (2 > 3)["yes"]["no"] ; a: "no"
|
|
|
|
a: (2 > 3)? -> "yes" -> "no" ; a: "no" (exactly the same as above)
|
|
|
|
|
|
|
|
; case/when statements
|
|
|
|
case [1]
|
|
|
|
when? [>2] -> print "1 is greater than 2. what?!"
|
|
|
|
when? [<0] -> print "1 is less than 0. nope..."
|
|
|
|
else -> print "here we are!" ; here we are!
|
|
|
|
|
|
|
|
;---------------------------------
|
|
|
|
; LOOPS
|
|
|
|
;---------------------------------
|
|
|
|
|
|
|
|
; with `loop`
|
|
|
|
arr: [1 4 5 3]
|
|
|
|
loop arr 'x [
|
|
|
|
print ["x =" x]
|
|
|
|
]
|
|
|
|
; x = 1
|
|
|
|
; x = 4
|
|
|
|
; x = 5
|
|
|
|
; x = 3
|
|
|
|
|
|
|
|
; with loop and custom index
|
|
|
|
loop.with:'i arr 'x [
|
|
|
|
print ["item at position" i "=>" x]
|
|
|
|
]
|
|
|
|
; item at position 0 => 1
|
|
|
|
; item at position 1 => 4
|
|
|
|
; item at position 2 => 5
|
|
|
|
; item at position 3 => 3
|
|
|
|
|
|
|
|
; using ranges
|
|
|
|
loop 1..3 'x -> ; since it's a single statement
|
|
|
|
print x ; there's no need for [block] notation
|
|
|
|
; we can wrap it up using the `->` syntactic sugar
|
|
|
|
|
|
|
|
loop `a`..`c` 'ch ->
|
|
|
|
print ch
|
|
|
|
; a
|
|
|
|
; b
|
|
|
|
; c
|
|
|
|
|
|
|
|
; picking multiple items
|
|
|
|
loop 1..10 [x y] ->
|
|
|
|
print ["x =" x ", y =" y]
|
|
|
|
; x = 1 , y = 2
|
|
|
|
; x = 3 , y = 4
|
|
|
|
; x = 5 , y = 6
|
|
|
|
; x = 7 , y = 8
|
|
|
|
; x = 9 , y = 10
|
|
|
|
|
|
|
|
; looping through a dictionary
|
|
|
|
dict: #[name: "John", surname: "Doe", age: 34]
|
|
|
|
loop dict [key value][
|
|
|
|
print [key "->" value]
|
|
|
|
]
|
|
|
|
; name -> John
|
|
|
|
; surname -> Doe
|
|
|
|
; age -> 34
|
|
|
|
|
|
|
|
; while loops
|
|
|
|
i: new 0
|
|
|
|
while [i<3][
|
|
|
|
print ["i =" i]
|
|
|
|
inc 'i
|
|
|
|
]
|
|
|
|
; i = 0
|
|
|
|
; i = 1
|
|
|
|
; i = 2
|
|
|
|
|
|
|
|
;---------------------------------
|
|
|
|
; STRINGS
|
|
|
|
;---------------------------------
|
|
|
|
|
|
|
|
; case
|
|
|
|
a: "tHis Is a stRinG"
|
|
|
|
print upper a ; THIS IS A STRING
|
|
|
|
print lower a ; this is a string
|
|
|
|
print capitalize a ; tHis Is a stRinG
|
|
|
|
|
|
|
|
; concatenation
|
|
|
|
a: "Hello " ++ "World!" ; a: "Hello World!"
|
|
|
|
|
|
|
|
; strings as an array
|
|
|
|
split "hello" ; => [h e l l o]
|
|
|
|
split.words "hello world" ; => [hello world]
|
|
|
|
|
|
|
|
print first "hello" ; h
|
|
|
|
print last "hello" ; o
|
|
|
|
|
|
|
|
; conversion
|
|
|
|
to :string 123 ; => "123"
|
|
|
|
to :integer "123" ; => 123
|
|
|
|
|
|
|
|
; joining strings together
|
|
|
|
join ["hello" "world"] ; => "helloworld"
|
|
|
|
join.with:"-" ["hello" "world"] ; => "hello-world"
|
|
|
|
|
|
|
|
; string interpolation
|
|
|
|
x: 2
|
|
|
|
print ~"x = |x|" ; x = 2
|
|
|
|
|
|
|
|
; interpolation with `print`
|
|
|
|
print ["x =" x] ; x = 2
|
|
|
|
; (`print` works by calculating the given block
|
|
|
|
; and joining the different values as strings
|
|
|
|
; with a single space between them)
|
|
|
|
|
|
|
|
; templates
|
|
|
|
print render.template {
|
|
|
|
<||= switch x=2 [ ||>
|
|
|
|
Yes, x = 2
|
|
|
|
<||][||>
|
|
|
|
No, x is not 2
|
|
|
|
<||]||>
|
|
|
|
} ; Yes, x = 2
|
|
|
|
|
|
|
|
; matching
|
|
|
|
prefix? "hello" "he" ; => true
|
|
|
|
suffix? "hello" "he" ; => false
|
|
|
|
|
|
|
|
contains? "hello" "ll" ; => true
|
|
|
|
contains? "hello" "he" ; => true
|
|
|
|
contains? "hello" "x" ; => false
|
|
|
|
|
|
|
|
in? "ll" "hello" ; => true
|
|
|
|
in? "x" "hello" ; => false
|
|
|
|
|
|
|
|
;---------------------------------
|
|
|
|
; BLOCKS
|
|
|
|
;---------------------------------
|
|
|
|
|
|
|
|
; calculate a block
|
|
|
|
arr: [1 1+1 1+1+1]
|
|
|
|
@arr ; => [1 2 3]
|
|
|
|
|
|
|
|
; execute a block
|
|
|
|
sth: [print "Hello world"] ; this is perfectly valid,
|
|
|
|
; could contain *anything*
|
|
|
|
; and will not be executed...
|
|
|
|
|
|
|
|
do sth ; Hello world
|
|
|
|
; (...until we tell it to)
|
|
|
|
|
|
|
|
; array indexing
|
|
|
|
arr: ["zero" "one" "two" "three"]
|
|
|
|
print first arr ; zero
|
|
|
|
print arr\0 ; zero
|
|
|
|
print last arr ; three
|
|
|
|
print arr\3 ; three
|
|
|
|
|
|
|
|
x: 2
|
|
|
|
print get arr x ; two
|
|
|
|
print arr \ 2 ; two
|
|
|
|
; (using the `\` infix alias for get -
|
|
|
|
; notice space between the operands!
|
|
|
|
; otherwise, it'll be parsed as a path)
|
|
|
|
|
|
|
|
; setting an array element
|
|
|
|
arr\0: "nada"
|
|
|
|
set arr 2 "dos"
|
|
|
|
print arr ; nada one dos three
|
|
|
|
|
|
|
|
; adding elements to an array
|
|
|
|
arr: new []
|
|
|
|
'arr ++ "one"
|
|
|
|
'arr ++ "two"
|
|
|
|
print arr ; one two
|
|
|
|
|
|
|
|
; remove elements from an array
|
|
|
|
arr: new ["one" "two" "three" "four"]
|
|
|
|
'arr -- "two" ; arr: ["one" "three" "four"]
|
|
|
|
remove 'arr .index 0 ; arr: ["three" "four"]
|
|
|
|
|
|
|
|
; getting the size of an array
|
|
|
|
arr: ["one" 2 "three" 4]
|
|
|
|
print size arr ; 4
|
|
|
|
|
|
|
|
; getting a slice of an array
|
|
|
|
print slice ["one" "two" "three" "four"] 0 1 ; one two
|
|
|
|
|
|
|
|
; check if array contains a specific element
|
|
|
|
print contains? arr "one" ; true
|
|
|
|
print contains? arr "five" ; false
|
|
|
|
|
|
|
|
; sorting array
|
|
|
|
arr: [1 5 3 2 4]
|
|
|
|
sort arr ; => [1 2 3 4 5]
|
|
|
|
sort.descending arr ; => [5 4 3 2 1]
|
|
|
|
|
|
|
|
; mapping values
|
|
|
|
map 1..10 [x][2*x] ; => [2 4 6 8 10 12 14 16 18 20]
|
|
|
|
map 1..10 'x -> 2*x ; same as above
|
|
|
|
map 1..10 => [2*&] ; same as above
|
|
|
|
map 1..10 => [2*] ; same as above
|
|
|
|
|
|
|
|
; selecting/filtering array values
|
|
|
|
select 1..10 [x][odd? x] ; => [1 3 5 7 9]
|
|
|
|
select 1..10 => odd? ; same as above
|
|
|
|
|
|
|
|
filter 1..10 => odd? ; => [2 4 6 8 10]
|
|
|
|
; (now, we leave out all odd numbers -
|
|
|
|
; while select keeps them)
|
|
|
|
|
|
|
|
; misc operations
|
|
|
|
arr: ["one" 2 "three" 4]
|
|
|
|
reverse arr ; => [4 "three" 2 "one"]
|
|
|
|
shuffle arr ; => [2 4 "three" "one"]
|
|
|
|
unique [1 2 3 2 3 1] ; => [1 2 3]
|
|
|
|
permutate [1 2 3] ; => [[1 2 3] [1 3 2] [3 1 2] [2 1 3] [2 3 1] [3 2 1]]
|
|
|
|
take 1..10 3 ; => [1 2 3]
|
|
|
|
repeat [1 2] 3 ; => [1 2 1 2 1 2]
|
|
|
|
|
|
|
|
;---------------------------------
|
|
|
|
; FUNCTIONS
|
|
|
|
;---------------------------------
|
|
|
|
|
|
|
|
; declaring a function
|
|
|
|
f: function [x][ 2*x ]
|
|
|
|
f: function [x]-> 2*x ; same as above
|
|
|
|
f: $[x]->2*x ; same as above (only using the `$` alias
|
|
|
|
; for the `function`... function)
|
|
|
|
|
|
|
|
; calling a function
|
|
|
|
f 10 ; => 20
|
|
|
|
|
|
|
|
; returning a value
|
|
|
|
g: function [x][
|
|
|
|
if x < 2 -> return 0
|
|
|
|
|
|
|
|
res: 0
|
|
|
|
loop 0..x 'z [
|
|
|
|
res: res + z
|
|
|
|
]
|
|
|
|
return res
|
|
|
|
]
|
|
|
|
|
|
|
|
;---------------------------------
|
|
|
|
; CUSTOM TYPES
|
|
|
|
;---------------------------------
|
|
|
|
|
|
|
|
; defining a custom type
|
|
|
|
define :person [ ; define a new custom type "Person"
|
|
|
|
name ; with fields: name, surname, age
|
|
|
|
surname
|
|
|
|
age
|
|
|
|
][
|
|
|
|
; with custom post-construction initializer
|
|
|
|
init: [
|
|
|
|
this\name: capitalize this\name
|
|
|
|
]
|
|
|
|
|
|
|
|
; custom print function
|
|
|
|
print: [
|
|
|
|
render "NAME: |this\name|, SURNAME: |this\surname|, AGE: |this\age|"
|
|
|
|
]
|
|
|
|
|
|
|
|
; custom comparison operator
|
|
|
|
compare: 'age
|
|
|
|
]
|
|
|
|
|
|
|
|
; create a method for our custom type
|
|
|
|
sayHello: function [this][
|
|
|
|
ensure -> is? :person this
|
|
|
|
|
|
|
|
print ["Hello" this\name]
|
|
|
|
]
|
|
|
|
|
|
|
|
; create new objects of our custom type
|
|
|
|
a: to :person ["John" "Doe" 34] ; let's create 2 "Person"s
|
|
|
|
b: to :person ["jane" "Doe" 33] ; and another one
|
|
|
|
|
|
|
|
; call pseudo-inner method
|
|
|
|
sayHello a ; Hello John
|
|
|
|
sayHello b ; Hello Jane
|
|
|
|
|
|
|
|
; access object fields
|
|
|
|
print ["The first person's name is:" a\name] ; The first person's name is: John
|
|
|
|
print ["The second person's name is:" b\name] ; The second person's name is: Jane
|
|
|
|
|
|
|
|
; changing object fields
|
|
|
|
a\name: "Bob"
|
|
|
|
sayHello a ; Hello Bob
|
|
|
|
|
|
|
|
; verifying object type
|
|
|
|
print type a ; :person
|
|
|
|
print is? :person a ; true
|
|
|
|
|
|
|
|
; printing objects
|
|
|
|
print a ; NAME: John, SURNAME: Doe, AGE: 34
|
|
|
|
|
|
|
|
; sorting user objects (using custom comparator)
|
|
|
|
sort @[a b] ; Jane..., John...
|
|
|
|
sort.descending @[a b] ; John..., Jane...
|
|
|
|
```
|
|
|
|
|
|
|
|
## Additional resources
|
|
|
|
|
|
|
|
- [Official documentation](https://arturo-lang.io/documentation/) - Arturo official documentation & reference.
|
|
|
|
- [Online playground](https://arturo-lang.io/playground/) - Online REPL for the Arturo programming language.
|