Nie rozumiem sensu programowania funkcyjnego

Odpowiedz Nowy wątek
2019-07-29 21:55
2

I podobnie jak w wątku poniżej nie chcę się kłócić, że "funkcyjne jest be", tylko naprawdę nie rozumiem.

Ostatnio mamy wielki trend który głosi, że "Programowanie funkcyjne jest dużo lepsze niż nie-funkcyjne". A w szczególności - lepsze niż wszystko, co imperatywne.

Niech im będzie. Ale dla mnie programowanie funkcyjne jak i argumentacje za nim sa naprawdę trudne do przełknięcia.

Po pierwsze: Dla mnie osobiście jest ono bardzo nieintuicyjne.

Ktoś na reddicie twierdził, że nieintuicyjność FP być może wypływa tylko z tego, że ludzie od początku są szkoleni do myślenia imperatywnego. Gdyby wyrzucić języki imperatywne ze szkół i zastąpić je funkcyjnymi, to myślenie funkcyjne byłoby równie intuicyjne.

Ja natomiast osobiście odnoszę wrażenie, że po prostu informatyka byłaby jeszcze bardziej znienawidzona przez większość uczniów.

Wydaje mi się, że dla człowieka naturalne jest myślenie czasownikami i w kategoriach zmieniającego się stanu.

Imperatywnie: Piszę na kartce zdanie Ala ma kota pod akapitem, który napisałem wcześniej.

Funkcyjnie: Niech k będzie dowolną kartką. k' jest kartką taką, że cały tekst napisany na k' jest identyczny z tekstem napisanym na k, a dodatkowo na k' jest jeszcze zdanie Ala ma kota poniżej jakiegokolwiek innego tekstu.

Nawet pisze się koślawo, co wskazuje, że język naturalny nie powstał do tego rodzaju opisu (bo ludzie tak nie myślą). Językiem ojczystym będzie tu raczej język matematyczny: k' = ιk∈K. tekst(k') = tekst(k) || "Ala ma kota". Tutaj dopiero to wygląda naturalnie; ale ludzie nie posługują się takim językiem na co dzień.

Gdzie tu są problemy? (a) Wyrzucamy czasowniki, bo one ze swej natury modyfikują stan; zamiast tego mamy myśleć deklaratywnie, a więc opisywać co czym jest, a nigdy: co się z czym odbywa. Jednak ludzie myślą czasownikami. (b) Co za tym idzie: Tworzymy nową kartkę. (WTF? Jak piszę na kartce to nie pojawia mi się stosik kartek po każdym napisanym słowie?) Wyrzucenie czasowników wywołuje eksplozję rzeczowników, wskutek czego zdawałoby się jeden i ten sam obiekt nagle opisywany jest wieloma rzeczownikami, a tak w ogóle to są to zupełnie różne obiekty.

Jednak tak nie jest w rzeczywistym życiu, skąd ludzie czerpią intuicje. Krojenie marchewki nie tworzy nowej marchewki. Włączenie telewizora nie powoduje, że w pokoju telewizor włączony zaczyna stać obok identycznego, ale wyłączonego.

Skądinąd zastanawiam się, co by było, gdyby przeprowadzić takie badanie: Wziąć tzw. "zwykłego człowieka" i programistę funkcyjnego i poprosić o wypowiedź na ten sam temat. Zanotować, jaka była u kogo proporcja rzeczowników do czasowników (wyjąwszy "być" i "mieć") oraz proporcja czasowników "być" i "mieć" do innych czasowników. Mam podejrzenia, że programista funkcyjny nawet na co dzień używałby mniej czasowników. Jestem ciekaw, co by z takiego badania wyszło. Bo jeśli moje przypuszczenia są prawdziwe - to jakby potwierdzało to, że bycie programistą funkcyjnym wymaga bardzo głębokich zmian w intuicji.

Po drugie: Współdzielony zmieniający się stan bywa wygodny!!

Na JPP na studiach był prikaz, by napisać interpreter wymyślonego przez siebie języka w Haskellu. To mnie zmusiło, by tego Haskella wreszcie spróbować.

Jakoś nie byłem zachwycony.

Wymyśliłem sobie język (imperatywny, ale z kilkoma nowatorskimi pomysłami). Tak - jest monada State. Pomocna przy takiej zabawie. Wśród licznych obiektów odpowiadających za stan mamy np. listę scope'ów. W moim języczku akurat nie było eksplozji możliwych dowiązań do tego samego scope'u, ale wciąż jednak pod pewnymi warunkami można się było dostać do tego samego scope'u z kilku różnych miejsc.

To natychmiast zaczęło wymagać, by każdy scope miał swój id. Scope nie mógł być dowiązany bezpośrednio do nazwy zmiennej - nie, nazwa zmiennej miała przechowywać id swojego scope'a.

Zamiast zatem prostego przejścia ze zmiennej do scope'a: Pobranie id, pobranie scope'a o tym id ze stanu przechowywanego w monadzie, zrobienie coś z tym scope'em, zapisanie nowego stanu... I tak jednolinijkowiec stawał się co najmniej trójlinijkowcem. (FP ma zmniejszać boilerplate w porównianiu do obiektówki)

I co za tym jeszcze idzie: Trzeba nagle eksplicite w ogóle deklarować tę listę scope'ów! W języku imperatywnym w ogóle takiej listy bym nie stworzył. Zamiast tego bym po prostu dołączał odpowiednie referencje.

(I co jeszcze za tym idzie, choć to już nie problem z mojego projektu, bo w moim języku z innych przyczyn i tak byłoby to niemożliwe: Problemy z automatycznym zarządzaniem pamięcią. Wyobrażam sobie, że gdybym pisał interpreter w nawet tej nieszczęsnej Javie (interpreter normalniejszego języka niż to, co wymyśliłem), to miałbym garbage collecting za darmo. Ginie ostatnia zmienna, która dowiązywała do jakiegoś scope'u? Brak jest dowiązań do scope'u, ginie i scope. W Haskellu? Ponieważ musi być centralny słownik wszystkich scope'ów, to dowiązanie do scope'a jest i wyciek pamięci gotowy.)

Co więcej: to wymuszało, by pojedyczne funkcje były naprawdę bardzo małe i robiły naprawdę tylko jedną rzecz. Dlaczego? Bo po zapisaniu zmian do monady trzeba... Pobrać dane z monady ponownie. Jeśli tego nie zrobię, to będę operował na nieaktualnych danych. To wymusza wyrzucanie każdej operacji pobierz/zapisz do osobnej funkcji, bo inaczej funkcja zaczyna być nieznośna. (Tak, pewnie ktoś zaraz powie, że "to dobrze bo i w obiektówce funkcje winny być jak najmniejsze - ciesz się, programowanie funkcyjne wymusza na tobie, co i tak powinieneś robić.)

Chodzi mi o to, że - jak dla mnie - w FP trzeba bardzo pilnować, by się stan nie rozsynchronizował. Ciągłe tworzenie nowych i jeszcze nowych obiektów łatwo może doprowadzić do tego, że skądś dojdziemy do nieaktualnych danych.

A teraz teoretycznie: Gra. Chociażby ta, którą dłubię. To wydaje się być po prostu w opór imperatywne: Jeden stworek wali drugiego więc drugi traci 20 HP. Chcę wykorzystać fakt, że można modyfikować stan globalny! Bo teraz za darmo mam już to, że to zmniejszenie się HP jest widoczne zewsząd: z listy stworków drużyny pojedynczego gracza, ze stworka, który właśnie zadał cios (referencja o wdzięcznej nazwie opponent), wszytkie efekty które zależą od HP też będą miały dostęp do aktualnego HP... W Haskellu nie miałbym tego. Gdybym po prostu zrobił dowiązania, to te dowiązania zdezaktualizowałyby się z chwilą zadania ciosu. A więc znów - centralny rejestr wszystkich stworków, jakieś sztuczne id tych stworków pewnie (aktualny przeciwnik nie jest zatem stworkiem tylko jakąś dziwną liczbą, na podstawie której trzeba dopiero pobrać stworka), i pewnie jeszcze to samo z wieloma innymi rzeczami, gdzie obecnie wykorzystuję dowiązania.

Globalny stan jest be - ale jak stworek oberwie to ja naprawdę chcę, żeby ze wszystkich innych miejsc w kodzie było widać zmniejszone HP!! A przecież w myśl paradygmatu funkcyjnego to jest właśnie tragedia, jeśli zmiana w jednym miejscu kodu propaguje się nagle do innych miejsc w kodzie. Tyle że dla mnie wyrzucenie takich propagacji wymusza komplikowanie kodu, jak opisałem na przykładach wyżej.

Jednak

Uznaję, że powyższe problemy mogą po prostu wynikać z tego, że nigdy nie nauczyłem się porządnie pisać funkcyjnie. Może po prostu próbuję przenosić praktyki, nawyki i intuicje z jęz. imperatywnych do jęz. funkcyjnych, widzę, że one jakoś nie pasują, więc odrzucam Haskella podczas gdy powinienem odrzucić te nawyki - czyli oduczyć się wszystkiego, co już umiem, i uczyć się na nowo.

Może zatem dla własnego dobra trzeba by się zmusić do pisania fukncyjnego, i powrócenia do tematu za pół roku albo i rok nawet - może po takim ćwiczeniu też bym nagle zaczął dostrzegać same zalety FP i już nigdy bym nie chciał z własnej woli pisać imperatywnie.

Nie za bardzo widzę, jak to zrobić w praktyce. W pracy mam Pythona na razie - nie chcę wykorzystywać zadań z pracy do nauki paradygmatu, z którym na razie nie za bardzo mi po drodze. Ucierpiałaby praca. Uczyć się tego sam dla siebie? Sam dla siebie piszę grę w C# - jak zacznę przepisywać ją na Haskella to chyba nigdy jej nie zrobię. Tzn będzie to może interesujące ćwiczenie pod wzgl. nauki Haskella, ale raczej będzie wymagało porzucenia marzeń o ukończeniu jej.

Tak, niby na upartego w C# DA SIĘ pisać funkcyjnie, ale znów to samo... zbyt wielkie skupienie na tym, JAK to mam robić doprowadzi do tego, że tego nie zrobię. Tym bardziej, że obecnie dostrzegam tylko upierdliwości na myśl o porzuceniu wszelkich side-effectów.

Uczyć się funkcyjnego jako trzecie zadanie, obok pracy i powyższej gry? Sorry.. doba ma 24h.

A jednak przejść nad tym do porządku dziennego nie mogę. Za wiele ludzi śpiewa peany na cześć FP. Naprawdę może być tak, że nie ucząc się go, krzywdzę wyłącznie samego siebie. I z własnego wyboru pozostaję niekompetentny.

W zasadzie nie wiem, co teraz z tym zrobić.

O kurczę, normalnie jestem influencerką ;) - Freja Draco 2019-07-29 22:02
@Freja Draco: Ano, wygląda. :) Ale moim zdaniem to zachęciłaś kilometry na godzinę / @kmph do opisania tego, do czego i tak się już zbierał od pewnego czasu. - Silv 2019-07-30 06:01
Uznaję, że powyższe problemy mogą po prostu wynikać z tego, że nigdy nie nauczyłem się porządnie pisać funkcyjnie. Może się naucz, napisz jakiś projekt w języku czysto funkcyjnym i wtedy się wypowiedz. Co myślisz? - nullpt4 2019-07-30 15:02
@nullpt4: Tak jak pisałem, już zostałem zmuszony do napisania projektu w języku czysto funkcyjnym - na studiach. I tak jak pisałem, z nauczeniem się naprawdę porządnie programować funkcyjnie jest ten problem, że nie za bardzo widzę, jak to zmieścić w dobie... - kmph 2019-07-30 18:01

Pozostało 580 znaków

2019-07-29 22:04
7

title

Pozostało 580 znaków

2019-07-29 22:16
3
  1. Jest tak samo intuicyjne jak imperatywne, ma po prostu inną składnie i inny sposób myślenia ;) Niby pisanie deklaratywnie jest dzwine, ale jakoś SQLa ludzie używają ;)
  2. Globalny stan tylko wydaje się fajny. Jeśli robisz coś sam, to może nie zrobisz głupty (chyba, że o czymś zapomnisz), ale pracując z kimś skąd masz gwarancje tego, że przypadkiem czegoś w 'ważnym' momencie nie zmieni?

Funkcyjnie kod gry miałbyś zupełnie inaczej napisany. Nie miałbyś jednego miejsca skąd pobierasz obecny stan, tylko aktualny stan byłby jednym z parametrów wywołania ruchu, a sam ruch zwracałby nowy stan. Ten zostałby przekazany dalej i tak w kółko. Nie trzeba o nic dbać, bo wszystko działa samo ;)


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.
edytowany 1x, ostatnio: danek, 2019-07-29 22:17
Nie miałbyś jednego miejsca skąd pobierasz obecny stan - monada State? - kmph 2019-07-30 18:03

Pozostało 580 znaków

2019-07-29 22:27
2

To co opisałeś to próba przetłumaczenia imperatywnego kodu 1:1 do Haskella. Oczywiście da się to robić, ale nie o to chodzi. Przykład takiego tłumaczenia to tłumaczenie kodu C typu:

void quicksort(int *A, int len) {
  if (len < 2) return;

  int pivot = A[len / 2];

  int i, j;
  for (i = 0, j = len - 1; ; i++, j--) {
    while (A[i] < pivot) i++;
    while (A[j] > pivot) j--;

    if (i >= j) break;

    int temp = A[i];
    A[i]     = A[j];
    A[j]     = temp;
  }

  quicksort(A, i);
  quicksort(A + i, len - i);
}

nie na idiomatycznego Haskella typu:

qsort [] = []
qsort (x:xs) = qsort [y | y <- xs, y < x] ++ [x] ++ qsort [y | y <- xs, y >= x]

ale na pokrakę symulującą 1:1 działanie kodu w C, czyli coś a'la (pseudokod, bo w Haskellu nie pisałem wieki):

qsort [] = return [] // return bo korzystamy z typu IO
qsort [a] = return [a]
qsort (as) = do
  pivot = as[len(as) / 2]
  i <- allocVariable
  j <- allocVariable
  putValue(i, 0)
  loop(
    return true,
    do
      putValue(i, getValue(i) + 1)
      putValue(j, getValue(j) - 1),
    do
      loop
  )
... i tak dalej, mnóstwo dziadostwa z monadami IO

Teoretycznie dałoby się napisać automat zamieniający postać z C (czyli tą pierwszą) na 1:1 odpowiednik Haskellowy (czyli tak trzecia postać z mnóstwem dziadostwa). Powstały kod były czysty funkcyjnie według definicji Haskellowców, ale od razu zaczęliby krzyczeć, że nie tak się pisze w Haskellu i w ogóle jest ideologiczny zakaz takiego pisania.

FP wymaga znacznej zmiany w organizacji kodu w porównaniu do kodu imperatywnego, by miało sens. Haskell ma natomiast tę cechę, że wymusza brak efektów ubocznych nieopakowanych w typ IO. Ja tam czasem wolę zrobić sobie jakąś lokalną mutację jeśli mi to znacznie ułatwia życie. Dlatego łączę programowanie imperatywne i funkcyjne w Scali, która daje dowolność łączenia paradygmatów :]


"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 2x, ostatnio: Wibowit, 2019-07-29 22:29

Pozostało 580 znaków

2019-07-30 07:26
0

Trochę hardkorowe (purystyczne?) podejście wybrałeś lecąc od razu w Haskella. Może spróbuj jak każdy, zacząć od filter/map/reduce zamiast pętli, i idąc dalej zobaczysz zalety i wady FP. Bardzo możliwe, że po prostu twoje problemy nie pasują do FP, do gier mi to średnio pasuje. No chyba że na siłę coś w stylu redux-a że jest globalny (tfu! xD) stan i akcje zmieniające go, ale pewnie ktoś się przyczepi i do tego :P

Pokaż pozostałe 4 komentarze
Sama operacja typu map/filter/reduce to nadal tylko operacja (i w świecie np. Javy głównie wykonywana na kolekcjach). Znajdzie się zapewne dużo osób, które dadzą jakiegoś println'a albo logowanie do map (co nie raz na żywo widziałem, stąd takie założenie) i już cała idea idzie w piach. Tak jak @Patryk27 powiedział, fakt, że gdzieś się zastosuje lambdę nie znaczy, że programuje się funkcyjnie. - DisQ 2019-07-30 18:18
Tylko ze te operacje zachowują idee niemutowalnosci - scibi92 2019-07-30 18:30
Stałe też są niemutowalne. Czy wykorzystując je w Javie mogę mówić, że programuję funkcyjnie? No niby tak, ale nie do końca. - Patryk27 2019-07-30 18:31
Idee niemutowalności może i zachowują, ale jeśli ktoś przeleci mapą po wszystkich elementach listy i dla każdego z nich pobierze encję z bazy to już nie zachowuje żadnego założenia FP. A na pewno wszyscy widzieli taki kod :) - DisQ 2019-07-30 18:38
Ale nikt nie mówi że Java to język funkcyjny. - scibi92 2019-07-30 18:49

Pozostało 580 znaków

2019-07-30 18:39
0

gdzie temat 'nie rozumiem sensu programowania proceduralnego'? :)

jako ze wiekszosc zycia pisze proceduralnie/oop to te pare epizodow w haskellu mi dalo duzo frajdy, ale mysle ze jest on strasznie upierdliwy do pisania rzeczy ktore klasycznie sie robi z mutowalnym stanem, moze zamiast tego wez jakies praktyczne zadanie ktore akurat bardziej do tego pasuje, np jak masz na cos wiecej czasu w pracy to zrob to w haskellu (jak to cos jest wylacznie dla ciebie oczywiscie). z takich rzeczy nie wymagajacych za duzo babrania sie z mutowaniem to np indekser/edytor do plikow, template engine, jakis konwerter miedzy skomplikowanymi formatami, cos do walidacji danych etc

Pozostało 580 znaków

2019-07-30 19:01
2

Po pierwsze programowanie funkcyjne wcale nie oznacza, że język musi być deklaratywny.
Ludzie z powodzeniem programują funkcyjnie w Java a nawet w C++ czy C.

Programowanie funkcyjne ma kilka zalet:

  • łatwo napisać testy do istniejącego kodu
  • nie ma mutowanych stanów czyli nie ma problemu z race condition, więc programowanie wielowątkowe jest dużo prostsze.
  • updgrade softu może być dużo bardziej proste, co jest pokazane w klasyku Erlang the movie

Sam nie praktykuje programowania funkcyjnego, ale zdecydowanie należy spróbować, bo to bardzo poszerza horyzonty.
To jedna z tych rzeczy, na które najpierw się narzeka, a jak się już załapie to stwierdza, że jest to super rozwiązanie. Sam chętnie bym zaliczył jakiś projekt z FP.

Z drugiej strony jak widzę jeszcze: Nie rozumiem sensu programowania obiektowego
To się zastanawiam czy to jakiś żart, wyścigi, czy wojna na paradygmaty programowania.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: cerrato, 2019-07-30 20:45
O to właśnie chodzi. Im więcej zasad, tym więcej pytań, czy coś jest z nimi zgodne. Gdyby nie było żadnego paradygmatu, nie pytano by o żaden, a tak niektórzy pytają o ten, a inni o tamten. Dla mnie rzecz naturalna w przypadku takiego jak obecnie zróżnicowania paradygmatów. - Silv 2019-07-30 22:31

Pozostało 580 znaków

2019-07-30 19:31
3

http://learnyouahaskell.com/ jest dobrym wstępem do FP.


"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.
Pokaż pozostałe 5 komentarzy
Jeśli poprawnie użyjesz np https://docs.oracle.com/javas[...]pi/java/util/WeakHashMap.html to nie będzie wycieków. - Wibowit 2019-07-31 21:30
Hmm ciekawe. A jak to by w Haskellu wyglądało? Także: Takie mapki siedzą w monadzie State czy też jest ideologiczny zakaz takiego pisania i należy je przekazywać w parametrach funkcji? - kmph 2019-07-31 21:43
W Haskellu byłoby ciężko: https://stackoverflow.com/q/4713906 W Javie/ Scali/ etc musiałbyś skonstruować tak typy, by nie dało się zauważyć odśmiecania, czyli np każdy nowy identyfikator musiałby być unikalny. Czy używać monady State? Szczerze to nigdy nie próbowałem pisać funkcyjnie gier i nie zastanawiałem się jakby to mogło wyglądać. - Wibowit 2019-07-31 21:55
http://hackage.haskell.org/pa[...]0.0/docs/System-Mem-Weak.html Czy Haskell jednak tego problemu nie rozwiązał? - kmph 2019-07-31 23:18
Musiałbym podrążyć temat jak to działa w Haskellu. W Scali mieszam podejście czysto funkcyjne i imperatywne, zamiast szukania za wszelką cenę eleganckich i zwięzłych rozwiązań funkcyjnych. Pewnie musiałbyś zapytać jakiegoś zapalonego Haskellowca o poradę. - Wibowit 2019-07-31 23:34

Pozostało 580 znaków

2019-08-09 00:57
0

Podepnę się ze swoimi wątpliwościami do tematu, bo wydaje mi się, że może to pomóc rozjaśnić problem.

Jakby co – nie znam się na programowaniu funkcyjnym, ale podoba mi się.

Zastanawiam się właśnie, jak inaczej podejść do operacji usuwania elementu z tablicy, jeśli stan tablicy ma być niezmienny (immutable). Sama operacja, np. w JavaScripcie, jest prosta – przykładowo:

const newArray = someArray.slice(1); // "newArray" zawiera wszystkie elementy "someArray" bez pierwszego

Tylko pojawia się problem: takiej operacji nie można już nazwać "usuwaniem element z tablicy", przynajmniej jak ja rozumiem "usuwanie z tablicy". Nie zostało nic usunięte z "obiektu" o nazwie "tablica" (nie mam tu na myśli "obiektu" w rozumieniu JavaScriptu, tylko ogólnie, w rozumieniu: "rzecz", "coś"). Oryginalna tablica nadal zawiera wszystkie elementy, które zawierała.

To jak inaczej takie "usuwanie" nazwać? Może w ogóle nie można nic "usunąć" (tym samym "dodać") w programowaniu funkcyjnym?

Dochodzę obecnie do wniosku, że "usuwanie" w tym rozumieniu nie istnieje w programowaniu funkcyjnym. Że istnieje coś na wzór "usuwania"; kluczowe znaczenie ma tutaj sposób myślenia o tej operacji.

Jak inaczej myśleć o "usuwaniu elementu z tablicy"? Można by tak:

  • W programowaniu nie-funkcyjnym mamy "obiekty" o nazwie "tablica", zawierające inne "obiekty"; tablice możemy zmieniać – dodawać elementy i usuwać.
  • W programowaniu funkcyjnym zaś mamy "obiekty", które są grupowane w większe "obiekty" zwane "tablicami"; w tym rozumieniu operacje "dodawania" i "usuwania" oznaczałyby po prostu inne pogrupowanie tych "obiektów".

Dobrze myślę?


edytowany 4x, ostatnio: Silv, 2019-08-09 00:59
Pokaż pozostałe 15 komentarzy
W sumie nie wiem jak tablice w FP dzialaja. Chodzilo mi tylko o to ze grupa to slaba analogia :p - stivens 2019-08-13 20:05
A jednak juz cos takiego implementowalem ale myslalem ze robie fuszerke XD In pure functional programs it is common to represent arrays by association lists. Association lists have the disadvantage that the access time varies linearly both with the size of the array (counted in number of entries) and with the size of the index (counted in cons nodes). - stivens 2019-08-13 20:10
To jest okazja, byś się douczył. ;) - Silv 2019-08-13 20:10
UP. Juz to implementowalem baaardzo prowizorycznie - stivens 2019-08-13 20:11
Tablicę możesz zaimplementować jak tylko chcesz. Np w Scali jest scala.collection.immutable.ArraySeq, gdzie jakakolwiek zmiana tworzy nową tablicę: https://github.com/scala/scal[...]tion/immutable/ArraySeq.scala Zamiast tego można jednak użyć i https://github.com/scala/scal[...]ection/immutable/Vector.scala który też można efektywnie indeksować, ale mamy też efektywne łączenie Vectorów, dodawanie czy usuwanie elementów, itd Vector to https://en.wikipedia.org/wiki/Persistent_data_structure z structural sharing. - Wibowit 2019-08-13 20:42

Pozostało 580 znaków

2019-08-09 01:24
2

Dziwne rzeczy.

  1. IMO myślenie tak zwanymi czasownikami to jeden z fundamentów programowania funkcyjnego.

  2. Poodejście imperatywne prowadzi do paradoksów - prędzej lub później. można je ignorować, ale są.
    Mnie się zawsze mózg skręcał jak widziałem zapis w stylu X = X+1 (chyba ktoś na głowę upad), mimo że to jeden z piewszych kodów jakie pisałem.
    Znam przypadki ludzi (2), którzy właśnie tej koncepcji nie mogli pojąć (zmiennych).

  3. No i ulegasz propagandzie:

A teraz teoretycznie: Gra. Chociażby ta, którą dłubię. To wydaje się być po prostu w opór imperatywne: Jeden stworek wali drugiego więc drugi traci 20 HP. Chcę wykorzystać fakt, że można modyfikować stan > globalny! Bo teraz za darmo mam już to, że to zmniejszenie się HP jest widoczne zewsząd: z listy stworków drużyny pojedynczego gracza, ze stworka, który właśnie zadał cios (referencja o wdzięcznej nazwie opponent), wszytkie efekty które zależą od HP też będą miały dostęp do aktualnego HP... W Haskellu nie miałbym tego.

Oczywiście masz to w haskellu:
http://hackage.haskell.org/pa[...]4.12.0.0/docs/Data-IORef.html

Różnica jest dość prosta - w Haskellu nie jest łatwo wrzucić psikusa, działania z side-effectami są jawne. W tym przypadku cokolwiek odczytuje z ioREF lub zmienia ioREf zostaje skażone przez IO. Dzięki temu wiadomo kiedy należy uważać. Kompilator przypomni.

IMO cały problem z językami i paradygmatami polega na punkcie widzenia, punkcie siedzenia i rozmiarze pisanych programów.
Jak piszesz proste skrypty do 100-1000 linijek to nie ogarniesz po kiego grzyba ludziom coś więcej niż JS, PHP, czy Python, a nawet bash.
Jak piszesz dla siebie gierki for fun to C#, Java i imperatywne podejście zwykle wystarcza.
Ale każdy rok wrzucania bugów na produkcje i rozczarowywania użytkowników powoduje, że szukasz koncepcji jak tu programować bezpieczniej, nawet jakby czasem trzeba było trochę bardziej pogłówkować.
Dla każdego praktycznie języka sa narzędzia typu sonar, lint itp. Języki funkcyjne maja część tych narzędzi niejako wbudowane.

Z tym, że nie jest tak, że fp to lek na wszystko. Problem jest taki, że podstawowy poziom dużo pomaga (niemutowalność chyba najwięcej). Ale każdy krok dalej wymaga ogarnięcia coraz większej ilości terminów ... i sam nie wiem czy to ma sens dla mainstreamu.

haskell ide


Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
edytowany 7x, ostatnio: jarekr000000, 2019-08-09 08:51
Pokaż pozostałe 4 komentarze
A. Hm. Nie pomogę na Windowsie, ale zawsze jest klawiatura ekranowa. - Silv 2019-08-09 01:31
To jakaś zabawna historia w 4 programmers. (Chrome, Firefox) - czasem literka ą robi psikusa... ale chwilowo już nie. - jarekr000000 2019-08-09 01:32
Może masz jakąś kombinację klawiszy ustawioną na dwie akcje – jedna akcja widoczna (np. kopiowanie za pomocą CTRL+C, czy też powielanie linijki w VS Code za pomocą CTRL+ALT+SHIFT+UP/DOWN), a druga akcja niewidoczna. I ta niewidoczna "wyłącza"/"włącza" ALT. - Silv 2019-08-09 01:34
PS. To znaczy nie musi być to "włączanie"/"wyłączanie" ALT-u explicite. Może ta niewidoczna akcja włącza jakąś usługę w tle, lub program, lub przełącza jakieś dwa parametry w systemie. Wtedy jeszcze inny działający program/usługa, która byłaby zależna od tych parametrów, "włącza"/"wyłącza" ALT zgodnie z nimi. - Silv 2019-08-09 01:38
Society if Haskell had IDE? Przecież mają: http://leksah.org/ - Wibowit 2019-08-13 13:44

Pozostało 580 znaków

2019-08-09 09:01
1
jarekr000000 napisał(a):

Dziwne rzeczy.

  1. IMO myślenie tak zwanymi czasownikami to jeden z fundamentów programowania funkcyjnego.

A czasowniki to nie obiektowka? W koncu w obiektowce dodajemy do listy a w FP...

(cons x current_list)

... a w FP wyrazenie wyzej ma wartosc rowna liscie z x'sem w glowie i current_list w ogonie. W szczegolnosci niczego nie dodalismy bo jezeli gdzies jest jeszcze referencja do starej listy to ona o nowej glowie nie wie. Zadnego czasownika tutaj nie ma? Wiec myslimy wartosciami a nie czynnosciami?


01010100 01110101 01110100 01100001 01101010 00100000 01101110 01101001 01100101 00100000 01101101 01100001 00100000 01101110 01101001 01100011 00100000 01100011 01101001 01100101 01101011 01100001 01110111 01100101 01100111 01101111 00101110 00100000 01001001 01100011 00100000 01110011 01110100 01101111 01101110 01110100 00101110
edytowany 2x, ostatnio: stivens, 2019-08-09 09:13

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0