Ridgun
The language itself: a compiler that compiles itself, the stable project tool, the specification and the book
| 1 | # Capítol 03: Funcions, signatures de tipus i l'art d'escriure codi com una taula |
| 2 | |
| 3 | Hi ha una pregunta que tot programador es fa la primera vegada que veu codi funcional: |
| 4 | |
| 5 | > *"Si aquí no hi ha classes, ni objectes, ni variables que canvien de valor... aleshores on fico la meva lògica?"* |
| 6 | |
| 7 | En **funcions**. Però no en aquelles funcions de 200 línies plenes de banderes booleanes que tots hem patit alguna vegada, sinó en funcions petites, directes i tan fàcils de llegir que semblen una taula en una pissarra. |
| 8 | |
| 9 | Vegem com es construeixen. |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## 3.1. Dues maneres de presentar una funció (Tu tries el vestit) |
| 14 | |
| 15 | En Ridgun tota funció comença amb la seva **signatura de tipus** (què entra i què surt després de `=>`) i a sota hi van les seves **clàusules d'implementació** (amb `=`). |
| 16 | |
| 17 | Pots escriure la capçalera de dues maneres: |
| 18 | |
| 19 | ### Opció A: Directa al gra (sense prefix) |
| 20 | ```ridgun |
| 21 | aplicar descompte Int Int => Int |
| 22 | aplicar descompte preu percentatge = preu - (preu * percentatge / 100) |
| 23 | ``` |
| 24 | |
| 25 | ### Opció B: Amb etiqueta explícita (`fn ::`) |
| 26 | ```ridgun |
| 27 | fn :: aplicar descompte Int Int => Int |
| 28 | aplicar descompte preu percentatge = preu - (preu * percentatge / 100) |
| 29 | ``` |
| 30 | |
| 31 | *"Escolta, i per què existeixen totes dues?"* |
| 32 | Perquè per a gustos, els colors: |
| 33 | - Hi ha qui prefereix que les funcions comencin enganxades al marge esquerre sense escriure `fn ::` cada vegada (al cap i a la fi, la fletxa `=>` ja crida als quatre vents que aquella línia és una signatura de tipus). |
| 34 | - I hi ha qui prefereix tenir una columna esquerra dedicada a les etiquetes (`fn ::`, `op ::`, `type`, `import`) per escanejar el fitxer visualment. |
| 35 | |
| 36 | El compilador i `stable format` entenen totes dues a la perfecció. A més, les paraules `fn` i `op` es poden fer servir lliurement com a part del nom de qualsevol funció o operador (per exemple `fn :: op`, `op :: fn` o `op :: op`), i si una funció retorna múltiples valors, en mode canònic/estricte els tipus de sortida s'escriuen separats per espais després de `=>` (`dividir amb residu Int Int => Int Int`). |
| 37 | |
| 38 | --- |
| 39 | |
| 40 | ## 3.2. La màgia de les columnes: per què els teus ulls descansen |
| 41 | |
| 42 | Mira aquesta funció que calcula el cost d'un enviament segons el país i si és urgent: |
| 43 | |
| 44 | ```ridgun |
| 45 | cost enviament String Bool Int => Int |
| 46 | cost enviament "ES" False _ = 5 |
| 47 | cost enviament "ES" True _ = 12 |
| 48 | cost enviament _ False pes = 10 + (pes * 2) |
| 49 | cost enviament _ True pes = 25 + (pes * 4) |
| 50 | ``` |
| 51 | |
| 52 | Fes la prova: tapa la meitat dreta de la pantalla i mira només les tres columnes d'entrada: |
| 53 | - Primera columna (`String`): `"ES"`, `"ES"`, `_`, `_`. |
| 54 | - Segona columna (`Bool`): `False`, `True`, `False`, `True`. |
| 55 | - Tercera columna (`Int`): `_`, `_`, `pes`, `pes`. |
| 56 | |
| 57 | Hi veus cap forat lògic? Cap ni un: hi ha les 4 combinacions possibles davant dels teus nassos, alineades verticalment sota `String`, `Bool` i `Int`. En un bloc d'`if / else` tradicional hauries de llegir 18 línies per estar segur que no t'has deixat cap cas penjat. |
| 58 | |
| 59 | --- |
| 60 | |
| 61 | ## 3.3. Els tipus bàsics i un regal per no comptar zeros (`_KB`, `_MB`, `_GB`) |
| 62 | |
| 63 | Els tipus escalars de Ridgun són directes i sense sorpreses: |
| 64 | |
| 65 | | Tipus | Què és en realitat | Exemples | |
| 66 | |---|---|---| |
| 67 | | `Int` | Enter de 64 bits amb signe (`i64`) | `0`, `42`, `-100`, `0xFF00`, `1_000_000` | |
| 68 | | `U64` | Enter de 64 bits sense signe (`u64`) amb aritmètica modular i bit a bit nativa | `u64 0`, `u64 0x6a09e667f3bcc908`, `a ^ b`, `a << u64 13` | |
| 69 | | `Float` / `Real` | Decimal de doble precisió (`f64`) | `3.14159`, `0.001`, `-2.5` | |
| 70 | | `String` | Cadena de text immutable | `"Hola"`, `'ruta\crua'` | |
| 71 | | `Char` | Codi de caràcter | Retornat per `str char at` | |
| 72 | | `Bool` | Booleà de tota la vida | `True`, `False` | |
| 73 | | `()` | Buit (*Unit*, quan només imprimeixes o fas I/O) | `()` | |
| 74 | |
| 75 | ### Cansat d'escriure `65536` o `1048576` i resar per no haver-te menjat un dígit? |
| 76 | En Ridgun els literals numèrics accepten directament els sufixos **`_KB`**, **`_MB`** i **`_GB`**, a més de guions baixos `_` per separar grups de xifres: |
| 77 | |
| 78 | ```ridgun |
| 79 | mida buffer => Int |
| 80 | mida buffer = 64_KB -- El compilador ho tradueix a 65536 |
| 81 | |
| 82 | limit fitxer => Int |
| 83 | limit fitxer = 16_MB -- El compilador ho tradueix a 16777216 |
| 84 | |
| 85 | mascara octet => Int |
| 86 | mascara octet = 0xFF_00 -- Hexadecimal net i llegible |
| 87 | ``` |
| 88 | |
| 89 | --- |
| 90 | |
| 91 | ## 3.4. Cometes dobles (`"..."`) vs. Cometes simples (`'...'`) |
| 92 | |
| 93 | En molts llenguatges les cometes simples i dobles fan exactament el mateix (un malbaratament). En Ridgun cadascuna té una missió claríssima: |
| 94 | |
| 95 | ### 1. Cometes dobles (`"..."`): Intel·ligents i interpolades |
| 96 | Interpreten escapaments (`\n`, `\t`, `\"`, `\\`) i **avaluen qualsevol variable o expressió que posis entre claus `{...}`**: |
| 97 | |
| 98 | ```ridgun |
| 99 | resum comanda String Int Int => String |
| 100 | resum comanda item uts preu = |
| 101 | "Has demanat {uts}x {item}. Total a pagar: {uts * preu} euros." |
| 102 | ``` |
| 103 | |
| 104 | *(Truc: si necessites escriure una clau literal dins de cometes dobles —per exemple en generar un script de shell `"$\{VAR:-default\}"` o un JSON—, pots escapar-la amb barra invertida `\{` i `\}` o duplicar-la `{{` i `}}`).* |
| 105 | |
| 106 | ### 2. Cometes simples (`'...'`): Crues i literals (*Raw Strings*) |
| 107 | El que escrius entre cometes simples surt **tal qual**, sense tocar ni una barra invertida `\`, ni una clau `{}`. Perfecte per a quan generes codi en un altre llenguatge, escrius ordres de shell o treballes amb rutes plenes de barres: |
| 108 | |
| 109 | ```ridgun |
| 110 | ordre sed => String |
| 111 | ordre sed = 's/\([0-9]+\)/[\1]/g' |
| 112 | ``` |
| 113 | |
| 114 | ### La teva caixa d'eines per a cadenes (`String`) |
| 115 | Unir cadenes és tan simple com sumar-les amb `+`: `"Hola, " + nom`. I quan necessites fer cirurgia fina sobre un text, tens aquestes funcions natives a punt sense importar res: |
| 116 | |
| 117 | - `str len s` $\rightarrow$ longitud de `s`. |
| 118 | - `str char at s i` $\rightarrow$ codi numèric (`Int`) del caràcter a la posició `i` (`-1` si et passes). |
| 119 | - `str slice s inici fi` $\rightarrow$ retalla des d'`inici` fins a `fi` (sense incloure `fi`). |
| 120 | - `char from code c` $\rightarrow$ converteix un codi numèric (`Int`, p. ex. `10` per a `\n` o `34` per a `"`) en un `String` d'1 caràcter. |
| 121 | - `str contains s agulla` i `str starts with s prefix` $\rightarrow$ retornen `True` o `False`. |
| 122 | - `int to str n` i `str to int s` $\rightarrow$ converteixen de número a text i viceversa (`str to int` entén fins i tot `"0xFF"`!). |
| 123 | |
| 124 | --- |
| 125 | |
| 126 | ## 3.5. Blocs de diverses línies, la regla universal de l'`=` i variables `mut` |
| 127 | |
| 128 | Quan una funció no cap en una sola línia, fas un salt de línia després de l'`=` i sagnes el bloc. |
| 129 | |
| 130 | Mira com es llegeix un bloc pas a pas: |
| 131 | |
| 132 | ```ridgun |
| 133 | calcular factura Int Int => Int |
| 134 | calcular factura base iva_pct = |
| 135 | impostos = base * iva_pct / 100 |
| 136 | despeses_gestio = 5 |
| 137 | echo "Desglossament -> Base:" base "Impostos:" impostos |
| 138 | base + impostos + despeses_gestio |
| 139 | ``` |
| 140 | |
| 141 | Quatre regles d'or que fan que els blocs en Ridgun siguin nets i uniformes: |
| 142 | 1. **Immutable per defecte sense `let` ni `const`**: escrius `impostos = ...` i ja tens la teva constant local immutable. Si per descuit intentes sobreescriure `impostos = 99` més avall en el mateix bloc, el compilador et frena en sec. |
| 143 | 2. **Variables mutables explícites amb `mut`**: quan de debò vols anar actualitzant un acumulador local pas a pas dins d'una funció, el declares amb **`mut`** i després el reassignes lliurement amb `=`: |
| 144 | ```ridgun |
| 145 | aplicar recarrecs Int => Int |
| 146 | aplicar recarrecs preu = |
| 147 | mut total = preu |
| 148 | total = total + 10 |
| 149 | total = total * 2 |
| 150 | total |
| 151 | ``` |
| 152 | *(I si `total` desa una llista o estructura en memòria, la política **`RMM2`** de Ridgun suma `+1` al nou valor abans de descomptar `-1` a l'antic, alliberant-lo a l'instant si ningú més el fa servir).* |
| 153 | 3. **La regla universal de l'`=`**: darrere de **qualsevol `=`** (en una funció, en un operador, en una variable local `x =` o en una branca condicional) pots posar sempre qualsevol de les tres formes de bloc de Ridgun: |
| 154 | - **`(res)`**: línies seqüencials sagnades (com a dalt). |
| 155 | - **`|`**: un arbre de guardes condicionals. |
| 156 | - **`||`**: un graf de càlculs en paral·lel amb `->`. |
| 157 | 4. **L'última expressió és sempre el resultat**: `base + impostos + despeses_gestio` és el que retorna `calcular factura`. Sense `return`. |
| 158 | |
| 159 | Al **Capítol 04** veurem com prendre decisions complexes —incloent-hi arbres de decisió de diversos nivells amb `|.`— sense escriure mai un `if/else` ni un bucle `while`: benvingut al món de les **guardes booleanes** i la **recursió de cua de cost zero**. |