Scala - czego unikać, dobre rady na początek

Scala - czego unikać, dobre rady na początek
OL
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 miesiące
  • Postów:28
1

Zacząłem naukę Scali, głównie z myślą o nauce Sparka. Wiem, że mógłbym użyć do tego Javy, ale skoro i tak nie ma w tym kraju pracy dla ludzi z moim wykształceniem :P to stwierdziłem, że utrudnię sobie zadanie i wykorzystam ten czas do nauki czegoś nowego. Urzekł też mnie na swój sposób Vavr więc zrobię krok dalej przynajmniej jeżeli chodzi o podstawy i zobaczymy jak pójdzie. Zdaję sobie również sprawę, że w każdym języku można pisać kod działający, ale niekoniecznie sensowny biorąc pod uwagę specyfikę użytego języka.

Dlatego zwracam się z prośbą o wskazówki.

Na co zwrócić szczególną uwagę?
Co powinno się robić w tym języku, a czego absolutnie nie?
Jakich naleciałości z Javy unikać?

Póki co mam takie przemyślenia.

  1. Immutability uber alles! Swoją drogą czy nie uważacie, że val powinno być wartością defaultową dla pól?
  2. Rekurencja, rekurencja ogonowa, akumulatory. Z tym chyba mam póki co największy problem. Ciężko przestawić się na takie myślenie. Mam nadzieję, że to kwestia treningu.
  3. Unikać stosowania pętli. W kursie na Udemy pada wręcz stwierdzenie, że jeżeli chcesz użyć pętli while to znaczy, że robisz to źle. Używaj rekurencji.
  4. Pisać bez efektów ubocznych. Jak to rozumieć? Ja to interpretuje w ten sposób, że za każdym razem jeżeli dokonujemy jakiejś operacji na obiekcie to należy zwrócić jego nową instancję lub zmapować na inny typ.

Na ten moment na tyle.

Silv
Hm, nie znam Scali, niemniej ciekawe – rzadko widuję widzę wskazówkę, by używać rekurencji zamiast pętli. Jeśli już nie używać pętli, to zamieniając ją na funkcje wyższego rzędu (np. map, którą wspomniał @elwis poniżej).
jarekr000000
@Silv Pętli w funkcyjnym programowaniu sie nie używa. Co zresztą wynika z punktu 1 i 4. W takim kotlinie, (któremu daleko do scali) nie wiem nawet jak zrobić pętle - nigdy tego nie potrzebowałem.
Charles_Ray
Rekurencja ogonowa tak naprawdę jest pętlą po skompilowaniu :)
jarekr000000
@Charles_Ray: chcesz nagrodę za to odkrycie? Jeszcze odkryj, że java po skompilowaniu korzysta z goto (goto w bytecode /jmp w asm).
Silv
@jarekr000000: kurczę, nie przyszło mi do głowy, że chodzi o programowanie funkcyjne. ;) Zresztą też nie jestem w nim biegły. Ale teraz brzmi to trochę bardziej sensownie. Generalnie ja sobie póki co myślę o rekurencji jako o czymś, co się wybiera intencjonalnie, a nie domyślnie.
elwis
  • Rejestracja:ponad 18 lat
  • Ostatnio:19 dni
2

Chyba dobrze sprawy ująleś, raczej staraj się używać definicji funkcji ze znakiem równości (zamiast tych z klamrą), ciesz się parametrami klas, zapomniałeś wspomnieć o używaniu funkcji jako parametrów i funkcji anonimowych. Skoro rekurencja to dla ciebie coś nowego, to nie zapomnij o funkcjach map, fold, filter, itp. Chociaż też bez popadania w przesadę, czasem można sobie pozwolić na odrobinę imperatywnego programowania, zwłaszcza jeśli używasz javowego API, które nie pozostawia wyboru — po prostu opakowujesz to i na wyższym poziomie już robisz funkcyjnie. Jak zrozumiesz po co się pisze kod funkcyjny, myslę, że zrozumiesz. :)
Co do skutków ubocznych, to głównie chodzi o to, żeby wynik działania funkcji zależał tylko i wyłącznie od parametrów, w szczególności nie używać zmiennych globalnych. Jednak i tutaj, bez przesady, jak musisz skontaktować się z bazą danych, zrobić jakieś I/O to nie ma raczej opcji. Najważniejsze, żeby możliwie te kawałki odseparować od reszty.


edytowany 1x, ostatnio: elwis
Silv
"(…) ciesz się parametrami klas (…)" ;)
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:dzień
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
1

@elwis:

jak musisz skontaktować się z bazą danych, zrobić jakieś I/O to nie ma raczej opcji.

Jak to nie ma opcji? Po to mamy monady IO i insze, żeby robić czyste funkcje, które zależą tylko od argumentów, nawet jeśli trzeba pogadać z brudnym światem zewnętrznym.
Ale jak ktoś się uczy scali to na początku można to olać.a


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 1x, ostatnio: jarekr000000
elwis
A to nie podchodzi pod sugestię właściwego odseparowania tego kodu?
jarekr000000
Jak twój cały kod to operacje IO, to trudno by to sensownie odseparować. Separacja idealna jest taka - wszystko czysto i tylko na końcu w main - jedno jedyne unsafeRun czy jakieś unsafePerformIO. (Haskell idzie krok dalej i to unsafe wywołuje za programistę - przez co w kodzie można nie mieć żadnego dysfunkcyjnego syfu).
OL
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 miesiące
  • Postów:28
0

Co rozumieć przez unsafeRun? Dosłownie wykonanie zapytania do bazy czy też dajmy na to odczyt z pliku, które zwrócą nam None bądź też rzucą wyjątkiem? Czyli jako parametr przekazuje funkcję najniższego poziomu do głównej metody, a potem wynik operacji przetwarzam jak vavrowego eithera mapami i itp.?

Co do skutków ubocznych, to głównie chodzi o to, żeby wynik działania funkcji zależał tylko i wyłącznie od parametrów, w szczególności nie używać zmiennych globalnych.

A co ze zmianą stanu obiektu? Z jednej strony mogę sobie wyobrazić, że do każdego mapowania będziemy mieli nową instancję czy też nawet klasę, która będzie rozszerzała podstawowy obiekt, ale z drugiej może to oznaczać, że nam ilość prawie identycznych klas zacznie szybko puchnąć. Jednak jeżeli mielibyśmy się kurczowo trzymać tej zasady to nie powinno się używać setterów co samo z siebie wyniknie jeżeli ograniczymy się tylko do korzystania val. Tylko co w sytuacji jeżeli w momencie tworzenia obiektu nie mamy wszystkich danych i jakieś pole zostawimy niezainicjalizowane? Optymalnie czy też raczej poprawnie będzie wówczas mieć dwie klasy: początkową i rozszerzoną?

jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:dzień
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
1

Nie wiem czy to odpowie na pytanie co to znaczy unsfafeRun, bo przykład trochę zakłada, że to już wiemy, ale przykład jak to działa.

https://zio.dev/docs/getting_started.html

unsafeRun - to taka funkcja, która wykonuje program czysty (zapisany w postaci monady IO) na rzeczywistym świecie, gdzie są pliki, brud, awarie itd.
taka "profanacja".

A co ze zmianą stanu obiektu?

Nie ma takich rzeczy :-) (*)
Co do puchnięcia klas itd. - w pewnym sensie to prawda, programując funkcyjnie wykorzystuje sie tak do 10x więcej typów niż w analogicznym kodzie imperatywnym (obiektowym). Z drugiej strony - dzięki
type inference, tuples (krotki), first class function i kilku innym ficzurom jezyka - wcale tego nie widać - kod czasem przypomina dynamiczny jezyk w stylu js.

*
W praktyce - zmianę stanu w sposób czysty można zrobić korzystając z tzw. monady stanu. Przy czym monada stanu jest zupełnie czysta, nie ma tam żadnych brzydkich trików.
Można też odwołać się do czegoś w stylu Ref, które jest wewnętrznie nieczyste - taki odpowiednik wskaźnika w stylu funkcyjnym. Obiektu co prawda nie mutujemy, ale mamy wskaźnik na aktualną jego wersję (i możemy podmienić). To taka brudna alternatywa dla monady stanu. Używa się we frameworkach ze względu na wydajność i wygodę.


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 7x, ostatnio: jarekr000000
DQ
  • Rejestracja:prawie 10 lat
  • Ostatnio:6 miesięcy
  • Postów:141
0
olfeusz napisał(a):

Tylko co w sytuacji jeżeli w momencie tworzenia obiektu nie mamy wszystkich danych i jakieś pole zostawimy niezainicjalizowane? Optymalnie czy też raczej poprawnie będzie wówczas mieć dwie klasy: początkową i rozszerzoną?

Zależy od przypadku.

Możesz zamodelować takie pola jako Option i domyślnie mieć tam None:

Kopiuj
case class Person(firstName: String, maybeSecondName: Option[String])
val person = Person("abc", None)
...
val person2 = person.copy(maybeSecondName = Some("cdf")

W innych sytuacjach sensowniejsze może być zamodelowanie tego za pomocą kilku case class z transformacjami między nimi. Czego się nie wybierze to raczej nigdy nie następuje eksplozja prawie identycznych klas - zawsze się znajdzie na to jakiś sensowny sposób ;)

99xmarcin
  • Rejestracja:około 5 lat
  • Ostatnio:5 miesięcy
  • Postów:2420
1

Wygląda na to że trafiłeś na 2 w 1: Kurs Scali + Podstawy programowania funkcyjnego.

Rekurencja, rekurencja ogonowa, akumulatory. Z tym chyba mam póki co największy problem. Ciężko przestawić się na takie myślenie. Mam nadzieję, że to kwestia treningu.

W praktyce (a piszę to jako programista Scali 2 lata expa) poza fanatykami nikt tak nie pisze. Użycie foldów i rekrurencji to prosta droga do pisania przekombinowanego i nieczytelnego kodu. Jeżeli chcesz się nauczyć postaw FP to faktycznie warto takie ćwiczenia porobić żeby zrozumieć pewne koncepcje (tak jak dużo robi się dziedziczenia i hierarchii podczas nauki OOP). W produkcyjnym kodzie takie akademickie konstrukcje nie są już tak mile widziane...

Unikać stosowania pętli. W kursie na Udemy pada wręcz stwierdzenie, że jeżeli chcesz użyć pętli while to znaczy, że robisz to źle. Używaj rekurencji.

W kontekście Scali oznacza to że bardzo dużo rzeczy można zrobić za pomocą api strumieni (map/filter/take/drop/takeFirst/toList itp.) i pętle nie pojawiają się już tak często jak w java 8. Po prostu api strumieni jest o wiele bardziej zaawansowane. W kontekście twojego kursu: więcej wciskania FP ;)

Moje rady:

  • Używaj case class do modelowania danych.
  • Pisz krótkie czytelne metody. Twórz dużo klas.
  • Unikaj definiowania operatorów typu ++ czy :| - to nie jest czytelne.
  • Odpuść bardziej zaawansowane rzeczy jak HKT czy makra.
  • W skali jedną rzecz można napisać na 10 sposobów np. println { 1 }, znajdź dobry linter i używaj go od początku pozwoli Ci to wyłapać nieoczywiste błędy.
  • Użycie Java'owych bibliotek często ssie, lepiej znaleźć Scalowe nakładki lub odpowiedniki niż bujać się z konwersją Int <-> java.lang.Integer itp.

Z mojego blogu (ilustracja problemów z językiem):
http://blog.marcinchwedczuk.pl/scala-nesting-monads
http://blog.marcinchwedczuk.pl/passing-functions-as-arguments-in-scala-what-can-go-wrong
http://blog.marcinchwedczuk.pl/scala-wtf-1
http://blog.marcinchwedczuk.pl/pitfalls-of-using-Mockito-with-Scala

PS. Skala to niestety bardzo skomplikowany język i wymaga czasu zanim zostanie porządnie przyswojona. Tutaj dla przykładu kolejny wpis o pattern matchingu: http://blog.marcinchwedczuk.pl/ultimate-guide-to-scalas-match-expression który dobrze obrazuje złożoność języka...


Holy sh*t, with every month serenityos.org gets better & better...
edytowany 2x, ostatnio: 99xmarcin
Silv
:| – ciekawe operatory można w Scali zdefiniować. ;)
SW
Mnie kiedyś zniechęciły do Scali te dziwne operatory i frywolna składnia, ale teraz chciałbym do niej wrócić z C#, przynajmniej prywatnie. Próbowałem F#, ale tam jest ze 100 słów kluczowych :)
OL
Trafiłeś w punkt z tym, że to kurs scalowo-funkcyjny
NamingException
  • Rejestracja:około 4 lata
  • Ostatnio:około 4 lata
  • Postów:110
0
olfeusz napisał(a):
  1. Rekurencja, rekurencja ogonowa, akumulatory. Z tym chyba mam póki co największy problem. Ciężko przestawić się na takie myślenie. Mam nadzieję, że to kwestia treningu.

serio? A co z wydajnością? Przecież scala to jvm. I co z czytelnością?

Zobacz pozostałe 5 komentarzy
99xmarcin
nie przesadzajmy jak masz funkcje 10 linii, i zmienną k mutowalną to naprawdę Ci ta nimutowalność niwiele daje. Zasięg zmiennej i tak jest bardzo ograniczony. Za to czytelność cierpi...
jarekr000000
@0xmarcin: czytelność cierpi to jest bardzo subiektywne. Ja już od jakiegoś czasu nie ogarniam nawet bardzo prostego kodu z mutacjami. Wyszedłem z wprawy, jestem za stary- któraś z tych rzeczy.
NamingException
Czasem mam wrażenie, że cała ta scala jest po to by utrudniać sobie życie. Po to by senior developerzy, którzy już "wszystko" umieją, postawili przed sobą nowe wyzwania.
jarekr000000
@NamingException: tak samo patrzą developerzy PHP i JS na Javę i tą całą zabawę z typami.
OL
Moje pierwsze wrażenie jest takie, że Scala daje bardzo duże pole manewru w kontekście składni i jak się wychodzi ze sztywnych ram Javy to można ogłupieć. Przykład '+' może być legalną nazwą metody.
NN
NN
  • Rejestracja:ponad 5 lat
  • Ostatnio:około 4 lata
  • Postów:239
1

@NamingException: Rekurencja ogonowa w kwestii wydajności to trochę co innego niż zwykła rekurencja, ma możliwe optymalizacje: https://www.aptsoftware.com/scala-tail-recursion-optimisation-and-comparison-to-java/

KA
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:27
3

Tylko bezkształtne interpretery na wolnych monadach przy akompaniamencie kotów tagless final i dobrze skalibrowanej optyki.

Edit:

edytowany 2x, ostatnio: Kalrais
Zobacz pozostałe 8 komentarzy
KA
@jarekr000000: ja tam zawsze patrzyłem raczej w kierunku zaproponowanym przez Kiselyova - http://okmij.org/ftp/Haskell/extensible/more.pdf @Silv dodałem parę linków, żeby nie trzeba było szukać, ale tak jak pisze Jarek to nie jest najlepsza droga ;)
Silv
@jarekr000000: <zbiera materiały do nauki> To, to, to, to i… to! Tak na szybko. Bez przeglądania. Warto mieć jakieś punkty styczne z ekosystemem języka. Choćby same pojęcia. :)
Silv
@Kalrais: widzisz, a ja sam poszukałem, nie poczekałem na Ciebie. :/
KA
@Silv: to dobrze, bo to znaczy, że Ci się chce a to podstawa. :)
Silv
Chce mi się, bo mnie programowanie funkcyjne i ogólnie nowe rzeczy interesują. Jeśli mogę (tzn. mógłbym, gdybym miał czas) programować w Scali, to chcę ją znać, nawet teoretycznie. Tylko u mnie taka chęć to podstawa do porzucania zajęć, nim je skończę. To już przerobiłem. Więc niech sobie te linki polewitują w moich zakładkach, będę pamiętać, skąd są (Twoje też, @Kalrais ), a na razie będę kontynuować naukę sieci komputerowych. :) …Już zresztą poznałem pobieżnie, jeśli mogę się pochwalić, "circuit switching", "message switching" oraz "packet switching". :)
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:7 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
3
olfeusz napisał(a):

Zacząłem naukę Scali, głównie z myślą o nauce Sparka.

Nie chce nikogo rozczarowywać, ani tym bardziej obrażać, ale po przeczytaniu dwóch książek o Sparku zorientowałem się, że ludzie używający Sparka to nie są programiści tylko ludzie umiejący programować. Dokładniej ich nazwa zawodu to DataCośtam (nie pamiętam dokładnie, bo dużo się tych zawodów DataCośtam porobiło)

Co to oznacza? Jako nieprogramiści po prostu programują nie zastanawiając się nad Clean Code i innymi rzeczami. To że ich kod przypadkowo wygląda bardziej funkcyjnie niż kod w Javie 6 wynika z tego że MapReduce i podobnym algorytmom do przetwarzania danych po drodze z programowaniem funkcyjnym. Może w większych projektach są jakieś zasady, które się przestrzega bardziej niż w przykładach książkowych, ale na konferencjach słyszałem narzekania na specjalistów DataCośtam że dostarczają kod usiany zmiennymi aa i się tym nie przejmują. IHMO Prawdopodobieństwo znalezienia tam kogoś do rozmowy o wyższości monady ZIO nad State z Cats jest dość niskie.

Póki co mam takie przemyślenia.

Twoje przemyślenia są dobre, ale w Scali może być trudno ich przestrzegać, bo Scala jest funkcyjno imperatywna i daje wybór jak chcesz programować. A pokusa żeby zrobić imperatywny skrót jest duża.
Jak byś próbował pisać w Haskellu to wyboru byś nie miał. Tzn w Haskellu można napisać, kod który wygląda jak imperatywny, ale jest to dużo trudniejsze niż napisanie kodu w duchu Haskella czyli czysto funkcyjnie.

Unikać stosowania pętli. W kursie na Udemy pada wręcz stwierdzenie, że jeżeli chcesz użyć pętli while to znaczy, że robisz to źle. Używaj rekurencji.

Po zamianie pętli for na map/flatMap/fold tych miejsc na rekurencję wcale nie ma tak dużo. Zostają pętle while/do-while, ale to czasem też da się zamienić na funkcje biblioteczne. Np jeśli chcemy liczby Fibonacciego większe od 100, a mniejsze od 1000 to można liczby Fibonacciego zamodelować jako nieskończony leniwy strumień, a potem pobrać za pomocą funkcji bibliotecznych dropWhile i takeWhile, dzięki czemu nie mamy ani jawnej pętli, ani jawnej rekurencji.

BTW w Scali często warto użyć pętli for bo tak naprawdę nie jest to stricte pętla tylko mini język do przetwarzania monad czyli odpowiednik do-notation z Haskella. Oczywiście zarówno do-notation jak i pętli for w Scali nie należy nadużywać, bo istnieją funkcje biblioteczne, które robią to w czytelniejszy sposób. (Tylko że potem zostajemy z funkcjami typu liftM2, ale to już mój problem)


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
edytowany 2x, ostatnio: KamilAdam
OL
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 miesiące
  • Postów:28
0

To trochę jak byś wymagał od lekarza by miał dwie specjalizacje. Lub więcej. Zdarza się, ale rzadko. Osoby odpowiedzialne za stricte obrabianie danych mogą mieć inny zestaw umiejętności niż programista i dla nich może się liczyć przede wszystkim końcowy wynik, a to w jaki sposób go osiągną może być dla nich kwestią drugorzędną.

bo Scala jest funkcyjno imperatywna

Rzucam być może herezją, ale taka mnie naszła myśl, Czy czasami ta cała funkcyjność Scali to nie jest ściema w postaci przykrycia zaprojektowanej pod język obiektowy JVM nową składnią i możliwościami innego niż javowy kompilatora? No bo jeżeli zamiast anonimowej implementacji apply zastąpię to lambdą to przecież tak czy siak, co prawda nie wprost i to jest właśnie ta całość funkcyjność, wołam new Function().

KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:7 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
1
olfeusz napisał(a):

To trochę jak byś wymagał od lekarza by miał dwie specjalizacje. Lub więcej. Zdarza się, ale rzadko. Osoby odpowiedzialne za stricte obrabianie danych mogą mieć inny zestaw umiejętności niż programista i dla nich może się liczyć przede wszystkim końcowy wynik, a to w jaki sposób go osiągną może być dla nich kwestią drugorzędną.

Trochę schodzimy z tematu, ale dwóch na dwóch lekarzy w rodzinie mojej żony ma po dwie specjalizacje. Najpierw zrobili internę, ale opatrywanie ludzi z pourywanymi kończynami im się znudziło.
BTW Dwóch specjalizacji bardzo często wymagają od programistów nazywa się to fullstack lub developer + SysOps :(
BTW2 nie czepiam się ludzi od obrabiania danych, bardziej jestem zawiedziony że nie znajdę tam tego czego szukam, a szukam miejsce gdzie produkcyjnie używają programowania czystofunkcyjnego i monad :)

bo Scala jest funkcyjno imperatywna

Rzucam być może herezją, ale taka mnie naszła myśl, Czy czasami ta cała funkcyjność Scali to nie jest ściema w postaci przykrycia zaprojektowanej pod język obiektowy JVM nową składnią i możliwościami innego niż javowy kompilatora? No bo jeżeli zamiast anonimowej implementacji apply zastąpię to lambdą to przecież tak czy siak, co prawda nie wprost i to jest właśnie ta całość funkcyjność, wołam new Function().

Czy to jest ściema? Ogólnie JVM jest imperatywny, kompilator LLVM też ma imperatywny bitecode, komputery też są imperatywne. Komputera w pełni funkcyjnego chyba jeszcze nie zbudowano. Były kiedyś lisp-maszyny (dedykowane komputery do wykonywania Lispa), ale Lisp nie jest w 100% funkcyjny. Tak więc zawsze kompilowany język funkcyjny kończy jako imperatywny kod.
Tutaj jeszcze moje dwie myśli:

  • Obiektowość w Scali nie jest problemem (chociaż polimorfizm w OOP jest ułomny, lepsze są TypeClassy). Problemem jest imperatywny, zmienny stan.
  • Twórcy EtaLang (kompilatora Haskella na JVM) udowodnili że można tego JVMa przykryć taką ilością abstrakcji że nawet czystofunkcyjny kod się wykona.

Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)