Kiedy warto stosować programowanie funkcyjne?

Kiedy warto stosować programowanie funkcyjne?
Z6
  • Rejestracja:ponad rok
  • Ostatnio:ponad rok
  • Postów:6
0

Jak uważacie, w jakich sytuacjach programowanie funkcyjne jest optymalnym paradygmatem do rozwoju oprogramowania?

Cokolwiek przeczytam w internecie na ten temat to bardziej artykuły podkreślą łatwiejsze rozwiązywanie problemów związanych z współbieżnością lub łatwiejszym analizowaniem kodu, bo w czystych funkcjach nie ma efektów ubocznych więc jest mniej okoliczności, gdzie coś może pójść nie tak po naszej myśli.

Ale to do mnie niezbyt przemawia, albo inaczej, to ukazuje FP w dość słabym świetle, jako niszowy i bardzo niepraktyczny paradygmat, ponieważ większość aplikacji nie ma problemów z współbieżnością chyba, że 1) używa się ram, które mają magię, której nie idzie łatwo zrozumieć i od której nie można uciec lub 2) używa zbyt ograniczonych baz, które nie obsługują transakcji w stopniu w jakim wymaga aplikacja.

Wystarczy mieć posgresql i stosować pewniejsze ramy lub nawet brak ram, a większość potencjalnych problemów jakie rozwiązuje FP wydaje się na pierwszy rzut oka niedostrzegalne i nie warte podjęcia wysiłku.

Głowiłem się nie raz po co używać FP, tym bardziej gdy w komercyjnym projekcie pewne rzeczy się wykluczają jak np. używanie FP i postgresql. Tutaj transakcje mają charakter imperatywny. Próba pisania tego zgodnie z FP jest kuriozalna. Oczywiście zapytania są deklaratywne, ale blokady czy logika sterująca między nimi już nie więc robienie z tego czegoś deklaratywnego totalnie mija się z celem.

Dopiero z czasem zobaczyłem pewną korzyść jaka idzie w parze z FP, ale jeśli trochę się odpuści i stosuje FP tam gdzie ma większy sens.

Tutaj chciałem podzielić się moimi uwagami, myślę, że spostrzeżenie jest o tyle ciekawe, że sam wcześniej nie przeczytałem niczego podobnego/zbliżonego. Wydaje mi się, że ta rzecz powinna być podkreślana już na samym początku nauki funkcyjnych języków.

W przypadku FP, warto podkreślić, że jest to paradygmat jaki sprzyja właściwie przetwarzaniu gruboziarnistemu. W innych paradygmatach też dane można przetwarzać gruboziarniście, ale różnica w FP polega na tym, że tutaj mamy więcej opcji do zredukowania złożoności końcowego rozwiązania.

Klasycznie, by ogarnąć złożoność, kontrolować ją, posiłkujemy się różnymi abstrakcjami. Za abstrakcję uznaje się ten kod, który nie jest kodem biznesowym i który pod wpływem zmian wymań biznesowych projektu nie ulega zmianie. Czyli to taki niezmienny kod, którego definicja jest niemal stała. Dobrym przykładem są funkcje takie jak sort, min, max, sum.

Sytuacja w przypadku FP wypada o tyle ciekawiej, że więcej rzeczy można wyabstrahować, a to dlatego, że tworzenie kolekcji z innej kolekcji jest znacznie tańsze. Wynika to z niemodyfikowalności danych, w tym kolekcji i optymalizacji związanej z persistent data structures. Dzięki temu można pisać bez większych problemów rozbudowane wyrażenia z zagnieżdżonymi kolekcjami, które w efekcie końcowym mogą doprowadzić do powstania jakiś rozdmuchanych dokumentów choćby pdf, xml, html :D (wygodnie i to bez korzystania z silnika szablonów, co jest dla mnie pewnym odkryciem).

Wg mnie tym co warto podkreślić to właściwie wszystkie pośrednie operacje na zagnieżdżonych kolekcjach jakie tutaj można wyabstrahować, i użyć podczas pisania kodu biznesowego. Taki krok z jednej strony niweluje konieczność pisania wielu pętli w kodzie biznesowym, a z drugiej prowadzi do powstania kodu jaki można ponownie użyć.

Składanie operacji, bez pisania pętli sprzyja pracy na styku gdzie są zebrane dane i potrzeba analiza. Czyli w takich językach jak M, R czy J (osobiście w żadnym nie programowałem, ale one od razu odsłaniają to czego na początku nie widziałem). Myślę, że tego typu języki powinny być pierwszym wyborem jeśli ktoś chce spróbować z funkcyjnym programowaniem.

edytowany 4x, ostatnio: Riddle
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10051
1

Niektóre zasady z FP warto stosować wszędzie. Dla przykładu, mi się bardzo podoba pomysł nie redefiniowana wartości zmiennych (tzn raz ustalona, nie zmienia wartości, to samo z polami w obiektach) - i staram się to stosować wszędzie.

I szczerze mówiąc, poprawcie mnie jeśli się mylę, ale tylko tyle wystarczy żeby pisać funkcyjnie? Po prostu nigdy nie przypisuj zmiennej wartości więcej niż raz, i napisz cały kod tak żeby był immutable, wsadź IO w monadę, i możesz pisać funkcyjnie nawet w Pascalu.

Lambdy i flat mapy to jak rozumiem taki dodatek, konsekwencja wynikająca z tego? Taki dodatek do języka.

edytowany 2x, ostatnio: Riddle
elwis
  • Rejestracja:ponad 18 lat
  • Ostatnio:7 dni
0

Jak dla mnie są trzy możliwe powody, żeby nie używać FP: (1) Nie rozumienie go; (2) Nie można go zastosować (np. nie możemy użyć języka, który daje dobre wsparcie); (3) rozwiązujemy problem ad-hoc i imperatywne rozwiązanie jest trywialne. Jak się nie umie myśleć w kategoriach FP to rzeczywiście programowanie w ten sposób jest wyzwaniem, ale gdy się załapie to funkcyjnie jest po prostu łatwiej. Nie trzeba mieć z tyłu głowy wielu czynników, które mogą nie wynikać z kodu w oczywisty sposób, łatwiej testować i refaktorować. Co więcej rozwiązania funkcyjne, dobrze zrobione, są znacznie bardziej eleganckie i bardziej cieszą oczy.

Co do języków, to nie powiedziałbym, że R jest dobry do programowania funkcyjnego. Tak sobie, bym powiedział. Języki dobre do FP (moim zdaniem, które znam) to Haskell, Rust, Scala.Też Perl całkiem sobie radzi, ale to już nie ta klasa.


edytowany 2x, ostatnio: elwis
Z6
  • Rejestracja:ponad rok
  • Ostatnio:ponad rok
  • Postów:6
0

Nie wiem jak to jest we wszystkich językach, ale w clojure referencje można przysłonić. W zasadzie bardziej chodzi o to, by nie mutować. Generalnie jak zablokujesz mutowanie to właściwie tracisz z miejsca pętle, break, continue. Dla pętli potrzebujesz wystawić reduce, a żeby obejść break/continue leniwe wartościowanie i jakieś api do obracania wygenerowanymi sekwencjami.

elwis napisał(a):

Jak dla mnie są trzy możliwe powody, żeby nie używać FP: (1) Nie rozumienie go; (2) Nie można go zastosować (np. nie możemy użyć języka, który daje dobre wsparcie); (3) rozwiązujemy problem ad-hoc i imperatywne rozwiązanie jest trywialne. Jak się nie umie myśleć w kategoriach FP to rzeczywiście programowanie w ten sposób jest wyzwaniem, ale gdy się załapie to funkcyjnie jest po prostu łatwiej. Nie trzeba mieć z tyłu głowy wielu czynników, które mogą nie wynikać z kodu w oczywisty sposób, łatwiej testować i refaktorować. Co więcej rozwiązania funkcyjne, dobrze zrobione, są znacznie bardziej eleganckie i bardziej cieszą oczy.

Co do języków, to nie powiedziałbym, że R jest dobry do programowania funkcyjnego. Tak sobie, bym powiedział. Języki dobre do FP (moim zdaniem, które znam) to Haskell, Rust, Scala.Też Perl całkiem sobie radzi, ale to już nie ta klasa.

Nie znam tych języków M, R, J, ale koncepcja gdzie piszesz fragment kodu bez bezpośredniego posiłkowania się pętlą trochę zbliża się do filmów o hackerach lub gui z jakiego korzystają agenci CSI :-P

edytowany 1x, ostatnio: Riddle
loza_prowizoryczna
  • Rejestracja:ponad 2 lata
  • Ostatnio:3 dni
  • Postów:1592
0
Riddle napisał(a):

Lambdy i flat mapy to jak rozumiem taki dodatek, konsekwencja wynikająca z tego? Taki dodatek do języka.

To zależy czy ktoś poza wyciągnięciem pochodnej rozumie czym ona jest. To jest chyba główny argument dlaczego programowanie funkcyjne zazwyczaj nie warto stosować.


Przetrzyma wszystko
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 9 godzin
0
znowutosamo6 napisał(a):

Generalnie jak zablokujesz mutowanie to właściwie tracisz z miejsca pętle, break, continue. Dla pętli potrzebujesz wystawić reduce, a żeby obejść break/continue leniwe wartościowanie i jakieś api do obracania wygenerowanymi sekwencjami.

wszelakie pętle można zastąpić rekurencją ogonową. z drugiej strony, wstawianie rekurencji ogonowej gdzie popadnie strasznie by zaśmieciło kod i dlatego funkcyjne kolekcje (i inne funkcyjne typy danych) mają wiele kombinatorów (map, flatmap, reduce, groupby, filter, itp itd), które załatwiają blisko 100% zastosowań.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 5x, ostatnio: Wibowit
SL
  • Rejestracja:około 7 lat
  • Ostatnio:około 3 godziny
  • Postów:862
0

Tam, gdzie dużo logiki. Całe szczęście FP do tego celu można używać w każdym języku programowania. Nawet w takim pythonie mogę operować na niemutowalnych strukturach danych. Co prawda funkcje w śroku mogą być mutowalne, ale największą zaletą FP to właśnie wymuszone immutable, które sprawia, że design i przepływ programu jest prosty i testowalny

Riddle napisał(a):

Lambdy i flat mapy to jak rozumiem taki dodatek, konsekwencja wynikająca z tego? Taki dodatek do języka.

flatMap to warunek konieczny do monad. Sama monada to abstrakcja na temat wykonywania sekwencyjnych (to bardzo ważne) przekształceń, gdzie kolejne przekształcenia to właśnie flatMap.

hauleth
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:9 dni
1

Głowiłem się nie raz po co używać FP, tym bardziej gdy w komercyjnym projekcie pewne rzeczy się wykluczają jak np. używanie FP i postgresql.

Czemu niby się wykluczają? Absolutnie to nie jest prawda.

Ale to do mnie niezbyt przemawia, albo inaczej, to ukazuje FP w dość słabym świetle, jako niszowy i bardzo niepraktyczny paradygmat, ponieważ większość aplikacji nie ma problemów z współbieżnością chyba, że 1) używa się ram, które mają magię, której nie idzie łatwo zrozumieć i od której nie można uciec

No RAM zawsze musisz użyć, w taki czy inny sposób. Natomiast to co FP Ci daje to, że łatwiej jest śledzić przepływ danych w aplikacji, gdyż jedyny sposób w jaki funkcja może wpłynąć na dane jakie masz, to zwrócenie ich w zmodyfikowanej formie. Innymi słowy:

Kopiuj
data_copied = deep_copy(data)

f(data)

data == data_copied

Dla każdej funkcji f. Jest to rzecz, która znacząco ułatwia debuggowanie i testowanie aplikacji.

Do tego jeszcze jak masz bardziej rozbudowany system, to często też masz dodatkowe rzeczy, które robisz - np. współdzielone cache. W takim przypadku musisz uważać, by nie zmodyfikować przypadkowo danych we współdzielonym cache. Praktycznie każda większa współczesna aplikacja używa gdzieś współbieżności by mieć odpowiednią wydajność.

  1. używa zbyt ograniczonych baz, które nie obsługują transakcji w stopniu w jakim wymaga aplikacja.

Nie wiem w jaki sposób dobór DB ma tutaj jakiekolwiek znaczenie.

ale koncepcja gdzie piszesz fragment kodu bez bezpośredniego posiłkowania się pętlą trochę zbliża się do filmów o hackerach lub gui z jakiego korzystają agenci CSI

Niby czemu?


Dobrym przykładem gdzie FP się bardzo dobrze spisuje są wszelkiego rodzaju aplikacje sieciowe, ponieważ większość z nich działa na zasadzie:

Kopiuj
request -> process -> response

A wiesz co to przypomina? Aplikację funkcji w postaci process :: Request -> Response (± jakieś monady czy inne rzeczy by zadowolić system typów jeśli takowy mamy). Po prawdzie to dotyczy nie tylko aplikacji sieciowych, ale bardzo dużo innych systemów po prawdzie sprowadza się do tego prostego schematu. Więc jak widać większość serwerów bardzo ładnie pasuje nam do systemów FP.

No ale co z systemami, które np. utrzymują połączenie dłużej i są stanowe? No to też można łatwo zamodelować używając FP, bo dalej one opierają się na prostym request -> process -> response z tą różnicą, że jednocześnie trzymamy jakiś stan przez chwilę, więc mamy funkcję process :: State -> Request -> (State, Response) (czy podobną, w zależności już tutaj od konkretnego języka, ale sprowadza się to dalej do tego samego).


Zobacz pozostały 1 komentarz
Z6
Dobrym przykładem gdzie FP się bardzo dobrze spisuje są wszelkiego rodzaju aplikacje sieciowe, ponieważ większość z nich działa na zasadzie: request -> process -> response Zgodziłbym się, gdyby to było bezstanowe, a tak to jest oderwane od rzeczywistości.
Z6
Niby czemu? Właściwie to ze względu na kompozycje, łatwiej i szybciej można składać operacje by uzyskać konkretny wynik. Szybciej tak mi się pracuje w REPL gdy coś robię z danymi.
hauleth
Po kolei - nie wiem co mają transakcje do tego, bo nie widzę zbytnio ich imperatywności. A mutuje się zawsze, bo (prawie) każda aplikacja, która robi coś pożytecznego musi mutować. Po prostu nie da się inaczej. Ideą FP nie jest to, by się pozbyć mutowalności, ale to by ją ograniczyć na tyle, by uprościć pracę z kodę. Co do aplikacji sieciowych, możesz się nie zgadzać, ale całe mnóstwo aplikacji dokładnie tak działa i to działa bardzo dobrze. Argument z REPL jest uber zabawny, bo idea REPL wywodzi się z języka funkcyjnego (Lispa).
hauleth
Poza tym odpowiadaj w postach, a nie komentarzach.
Z6
@heuleth przy każdym komentarzu mam wrażenie, że nie zrozumiałeś mnie. Być może nie umiem pisać tak, aby być zrozumiany dlatego wstrzymam się z dalszym odpowiadaniem. W każdym razie dzięki za chęci i próbę nawiązania do dyskusji.
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:43 minuty
  • Postów:8398
1
znowutosamo6 napisał(a):

Jak uważacie, w jakich sytuacjach programowanie funkcyjne jest optymalnym paradygmatem do rozwoju oprogramowania?

programowanie funkcyjne rozwiązuje podobne problemy, które występują w innych rodzajach programowania, ale które inne rodzaje programowania rozwiązują w inny sposób.

jednym z tych problemów jest shared mutable state, czyli że jeśli masz pewien stan (zmienną, dane itp.) które się zmieniają i które są wykorzystywane w wielu miejscach w kodzie, to ciężko nad tym zapanować.

W OOP(ale i w proceduralnym paradygmacie można tak pisać) dąży się do tego, żeby ograniczyć miejsca w kodzie, gdzie następuje zmiana/odczyt danych - stosuje się hermetyzację (czyli zmienianie danych ma być ograniczone do obiektu, inne obiekty nie mają prawa dostępu do tych danych), programowanie sterowane przez eventy, wzorzec CQRS (Command and Query Responsibility Segregation - czyli oddzielamy mutację i odczyt) itp.

Czyli chodzi o to, żeby zapewnić, że dane będą się zmieniały tylko w kontrolowany sposób i żeby nie były rozsynchronizowane (bo jak masz jakiś kawałek kodu, który zmienia jakieś dane, to potem może się rozjechać, jeśli inny kawałek kodu będzie korzystał z tych samych danych w niekontrolowany sposób). Tutaj podoba mi się Rust, bo zawiera on mechanizmy na poziomie języka, które są w stanie tego pilnować, żeby dane były zmieniane w kontrolowany sposób.

Natomiast programowanie funkcyjne kasuje ten problem zmiany danych i używa niemutowalności (czyli raz ustawione dane się nie zmieniają. Wow, cała klasa problemów skasowana, bo po co zmieniać dane, jak można ich nie zmieniać? 💡). Plus stosuje jakieś bardziej zaawansowane mechanizmy i abstrakcje (nie będę się rozwodził nad nimi, bo je słabo znam).

postgresql. Tutaj transakcje mają charakter imperatywny.

Transakcje w bazach danych też można określić jako pewną kontrolę tego, żeby zmiany następowały w ściśle określony sposób.

Wystarczy mieć posgresql i stosować pewniejsze ramy lub nawet brak ram, a większość potencjalnych problemów jakie rozwiązuje FP wydaje się na pierwszy rzut oka niedostrzegalne i nie warte podjęcia wysiłku.

Ale czy jedno drugiemu przeszkadza? Baza danych to peryferia, a nie cała apka (chyba, że robisz coś, co faktycznie opiera się tylko i wyłącznie na bazie danych).


edytowany 8x, ostatnio: LukeJL
Z6
inne obiekty nie mają prawa dostępu do tych danych - mają nadal, lecz pośredni wpływ; więc nawet jak dane opakujesz w klasę to nadal mutujesz i współdzielisz dostęp (więc ogólnie zakres kodu, który doprowadza do mutowania jest tak samo obszerny jak wcześniej).
Z6
Baza danych to peryferia, a nie cała apka Dla mnie baza to centralna część systemu, która pozwala obsługiwać transakcje i przede wszystkim zabiegać o integralność danych. Natomiast programowanie funkcyjne kasuje ten problem zmiany danych i używa niemutowalności - dane trzymam w bazie i u mnie problem ten nie znika. dąży się do tego, żeby ograniczyć miejsca w kodzie, gdzie następuje zmiana/odczyt danych tu ograniczasz bezpośredni dostęp, ale pośrednio dalej można mutować wystarczy mieć instancje klasy by wywołać metodę
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)