Wątek przeniesiony 2021-04-03 15:26 z Algorytmy i struktury danych przez somekind.

Programowanie funkcyjne - dywagacje początkującego.

0

Chyba cel został osiągnięty. Niemal wszystkie funkcje czyste. Kod zrobił się nieco czytelniejszy.
To niebawem zasłużone piątkowe piwko a następnie idę poznawać monady. To podobno dalecy krewni dzikich fiordów...
@jarekr000000: czy już jest szansa na =3, tak zwane "czi na glajzach" bez części urojonych?

Całość tutaj:
https://ms.xksi.pl/3d-js-functional/
https://bitbucket.org/xksi/3d-js-functional/src/master/

const Graph = new classGraph( document.getElementById("screen") )
const pm = { "x":0, "y":0, "z":0, "s":5 }
const xC = Graph.maxX/2
const yC = Graph.maxY/2
const myForm = document.getElementById ('formParameters') // referencja do formularza

function drawTriangles( scene, pm ){
  scene.map( tr => { 
    Graph.triangle3d (
      xC + tr['pts'][0]['x'] * pm [ 's' ] * 800/(500+tr['pts'][0]['z']),
      yC + tr['pts'][0]['y'] * pm [ 's' ] * 800/(500+tr['pts'][0]['z']),
      xC + tr['pts'][1]['x'] * pm [ 's' ] * 800/(500+tr['pts'][1]['z']),
      yC + tr['pts'][1]['y'] * pm [ 's' ] * 800/(500+tr['pts'][1]['z']),
      xC + tr['pts'][2]['x'] * pm [ 's' ] * 800/(500+tr['pts'][2]['z']),
      yC + tr['pts'][2]['y'] * pm [ 's' ] * 800/(500+tr['pts'][2]['z']),
      Math.round ( 64 - tr['pts'][0]['z']/2 ) 
    );
  } )
}

function rotatePt ( pt, angle, da, db, dc ){
  return {
    [db]:(pt[db] * Math.cos( angle ) - pt[da] * Math.sin( angle )),
    [da]:(pt[da] * Math.cos( angle ) + pt[db] * Math.sin( angle )),
    [dc]:(pt[dc])
  }
}

function rotateTrVrt ( vrt, pm ){ 
  return rotatePt ( rotatePt ( rotatePt ( vrt,
         pm['x'], 'y', 'z', 'x' ),
         pm['y'], 'x', 'z', 'y' ),
         pm['z'], 'x', 'y', 'z' )
}

function rotateTr ( tr, pm ){  
  return { 'pts': tr['pts'].map ( vrt => rotateTrVrt ( vrt, pm ) ) }
}

function rotate( scene, pm ){  
  return scene.map ( tr => rotateTr ( tr, pm ) );
}

function userParams( pm, frm ){  
  // jedyna funkcja nieczysta bo korzysta z formularza.
  return {
    'x': pm [ 'x' ] + ( frm[ 'x' ].checked ? 0.01 : 0 ),
    'y': pm [ 'y' ] + ( frm[ 'y' ].checked ? 0.01 : 0 ),
    'z': pm [ 'z' ] + ( frm[ 'z' ].checked ? 0.01 : 0 ),
    's': parseFloat( frm['s'].value )/10,
    'obj': frm['obj'].value
  }
}

function animation( scene, pm ){
  Graph.clearScr()
  drawTriangles ( rotate ( scene, pm ), pm )
  setTimeout ( ()=>{ animation( scene, userParams ( pm, myForm ) ) }, 50 )
}

animation( scene, userParams ( pm, myForm ) )
1
koszalek-opalek napisał(a):

Inaczej na przykład w C++: możesz sobie narzucić czystość funkcji (umawiasz się ze sobą, że przekazujesz dane tylko przez wartość albo stałą referencję -- oraz zwracanie wartości returnem) i funkcje stają się czyste (no, jak jeszcze wyeliminujesz globalne zmienne itp.).

Sam fakt, że przekazujesz dane przez wartość czy stałą referencję nie powoduje, że funkcja staje się czysta. Zdecydowanie większym problemem jest kontrolowanie side-effectów i tutaj stosowany język ma większe znaczenie. Pomijając czy w ogóle język umożliwia modelowanie side effectów w "czysty" sposób, to przeogromne znaczenie ma czytelność kodu który się potem otrzyma.

3
DisQ napisał(a):
koszalek-opalek napisał(a):

Inaczej na przykład w C++: możesz sobie narzucić czystość funkcji (umawiasz się ze sobą, że przekazujesz dane tylko przez wartość albo stałą referencję -- oraz zwracanie wartości returnem) i funkcje stają się czyste (no, jak jeszcze wyeliminujesz globalne zmienne itp.).

Sam fakt, że przekazujesz dane przez wartość czy stałą referencję nie powoduje, że funkcja staje się czysta. Zdecydowanie większym problemem jest kontrolowanie side-effectów i tutaj stosowany język ma większe znaczenie. Pomijając czy w ogóle język umożliwia modelowanie side effectów w "czysty" sposób, to przeogromne znaczenie ma czytelność kodu który się potem otrzyma.

Oczywiście, zgadzam się -- efekty uboczne przede wszystkim. Częścią kontroli nad nimi jest właśnie to co napisałem, ale tylko częścią. Pisząc "staje się czysta" miałem oczywiście na myśli tylko pracę na danych, bez zewnętrznych efektów ubocznych, zmiennych globalnych itp.

Natomiast, w pewnym zakresie, czystość funkcyjna jest (moim zdaniem) łatwiejsza w C++ niż w JS, bo pomaga słówko const. Ale to takie tam dywagacje -- i tak powinno się programować w Haskellu. :)

3

Uważam, że najpierw można spokojnie dojść i poćwiczyć po prostu z "immutable" - to już dużo daje, relatywnie małym kosztem. Potem można wejść na level IO i efektów ubocznych, ale szat nie dre, nawet jak ktoś nie widzi sensu. Tu niestety, potrzeba doświadczenia i to w czystym, funkcyjnym języku.

2

Pracowalem okolo roku w projekcie pisanym w Haskellu. Jako entuzjasta bylem pozytywnie nastawiony. Po 6 miesiacach nie bylem w stanie pisac wiekszego niz kilkanascie linii kodu produkcyjnego. Przepasc pomiedzy mna a kolegami wyjadaczami byla przytlaczajaca. W projekcie byla gesto uzywane biblioteka Lens, co rowniez nie pomagalo.

Po prostu zmierzenie sie z kodem produkcyjnym po samouczkach "dla przedszkolakow" bylo dla mnie bolesne. Czytanie kodu kolegow bylo bolesne. Wiekszosci rzeczy byla bolesna. Czulem ze robimy sztuke dla sztuki.

Sam projekt szedl wolno, bylo duzo bugow,, integracja z innymi serwisami to byla masakra. Znalezienie ludzi chetnych do pracy - mega trudne.

Po roku pracy w tym projekcie przestalem byc fascynata FP i gdzie moge to 3 razy mysle czy ma pewno ten paradygmat bedzie zasadnym narzedziem do rozwiazania problemu.

Nie chce nikogo zniechecac. Dziele sie jedynie doswiadczeniem i polecam kazdemu fascynatowi napisac w Haskellu czy full FP Scala jakiejs aplikacji z obsluga nietrywialnych stanow czy program wymagajacy optymizacji a nie kolejny kompiler kodu czy inny parser aby wiedziec gdzie FP bedzie wygrywac, a gdzie bedzie bolec.

2
InterruptedException napisał(a):

Pracowalem okolo roku w projekcie pisanym w Haskellu. Jako entuzjasta bylem pozytywnie nastawiony. Po 6 miesiacach nie bylem w stanie pisac wiekszego niz kilkanascie linii kodu produkcyjnego. Przepasc pomiedzy mna a kolegami wyjadaczami byla przytlaczajaca. W projekcie byla gesto uzywane biblioteka Lens, co rowniez nie pomagalo.

Właściwie jakbym słyszał kolegów z embedded, którzy musieli coś robić przy kodzie OOP. Do tego nie poprawia sytuacji, że często takowy kod był pisany przez innych ludzi rodem z C.

Oczywiście trudno powiedzieć jaka była jakość tego kodu, ale skoro mówisz, że lens-y uwierały, to raczej niska - to flagowa biblioteka, która dobrze użyta bardzo poprawia czytelność kodu, ale źle użyta wszystko rozwala.

Widziałem ludzi, którzy grzebiąc się w pseudo oop nawet po roku nie ogarniali zbytnio tematu.

3

@InterruptedException

Po prostu zmierzenie sie z kodem produkcyjnym po samouczkach "dla przedszkolakow" bylo dla mnie bolesne. Czytanie kodu kolegow bylo bolesne. Wiekszosci rzeczy byla bolesna. Czulem ze robimy sztuke dla sztuki.

Ale tak to Ty możesz o wszystkim napisać. Jeśli ktoś np. nie pracował z PostgreSQL, a jedynie widział samouczki i wskoczy do projektu, gdzie są większe problemy to taka rzecz zajmuje czas i trzeba się przestawić, wiedzieć na co patrzeć itd. Mnie FP zajmuje już blisko 2-3 lata i wciąż nie jestem tak dobry jakbym chciał, cieszę się chociaż dostrzegam problemy i że z czasem odsłaniają mi się lepsze rozwiązania, ale sama droga jest w miarę długa i trzeba ten enuzjazm rozłożyć na dłużej.

Sam projekt szedl wolno, bylo duzo bugow,, integracja z innymi serwisami to byla masakra.

To jest ciekawe :-) Mógłbyś okreslić z czego wynikał problem?

Znalezienie ludzi chetnych do pracy - mega trudne.

Haskell i brak chętnych? Wiele osób by zgodziło się na mniejsze zarobki, by móc pracować z haskellem.. dlaczego problem z szukaniem? Słaby PR?

0

Krewetko. I tak i nie. Kontynuujac moja przygode. Gdy wskoczylem do innego projektu w innej firmie i zespole pisanego w pythonie, o ktorym wczesniej nie mialem wiekszego pojecia, bylem produktywny od pierwszego tygodnia.

Czyatnie kodu pythonowego bylo dla mnie proste. Pisanie bylo.nie za trudne. Biblioteki.mwga usprawnialy prace

Owszem, ciezko.porownywac te dwa zespoly. Inne produktu, wymagania, domena. Ale jednak co mi w sercu mowi, ze python jest latwiejszy do opanowania niz haskell.

Co.do integracji, pamietam, ze mielismy pribleny z ogarnieciem komunikacji kolejkowej z innymi serwisami, niestety, ciezko mi juz przypimniec sobie szczegoly.

A.dlaczego trudno bylo znalexc ludzi.do pracy. Nie wiem, moze rynek w Australii jest maly jezeli chodzi.o Haskella. Byc moze w Polsce byloby z talentem latwiej.

3

Może po prostu dobrze znasz paradygmat imperatywny, a nie funkcyjny i dlatego ten przeskok był dla Ciebie większy?

Bo przejście na funkcyjne pisanie wymaga pewnych zmian w "dogmantach"

2

Zaczęli się odzywać ludzie co FP liznęli i super bo wśród moich znajomych to jednak same dinozaury głęboko siedzące w OOP. Kolega @InterruptedException ma z tematu złe wspomnienia i przypuszczam, że miałbym podobnie. Raczej nie chciał bym trafić na projekt, który ma być w całości budowany w oparciu o FP. Po tych kilku dniach prób pisania i wielu godzinach oglądania wielu wykładów FP widzę go jako kolejne narzędzie / ideę pisania pewnych części systemów. Od OOP bym nie odchodził bo jednak ono jest dużo bliższe i bardziej naturalne podczas rozmów z "biznesem" a nawet innymi programistami, którzy jednak ciągle w większości myślą bardziej obiektowo niż funkcyjni.
Kolejna rzecz to to, że FP do pewnych zastosował po porostu się nie nadaje i koniec. Ja akurat chyba tak pechowo trafiłem, że w moim przypadku to jedynie przy front-endzie mógłbym zastosować na polu komercyjnym. Wszystko co robię albo wymaga dużych optymalizacji pamięci albo pracuje na dziesiątkach tysięcy rekordów lub na faktycznie dużych strukturach danych. Hobbystyczne też lipa bo albo obróbka dźwięku albo AVR, który ma 256 bajtów RAM:-)

Wstępnie wyczuwając ogólną ideę FP zauważyłem, że bardzo blisko tego tematu byłem pisząc pewien silnik wyszukiwania około 15 lat temu. Idea była taka aby każdy krok wyszukiwania był cacheowany to pociągało za sobą konieczność pisania czystych "klas" bo akurat u mnie to jest podstawowy klocek układanki. I faktycznie tak to działało każda klasa miała parametry wej. i jedną funkcję zwracającą wynik do kolejnych kroków, której wynik był zawsze deterministyczny dla tych parametrów. Do dziś tą ideę w swoich frameworkach kontynuuję. W ramach klasy pozwalam sobie jednak korzystać z pętli i zmiennych. Wiem, że to nie jest FP a jedynie kawałek idei, który moim zdaniem ma duże podobieństwa. Zresztą właśnie ta cecha FP spowodowała, że tematem się zainteresowałem.

Zawsze uważałem, że różne narzędzia trzeba znać i nie popadać w skrajności podczas korzystania z nich. To są tylko narzędzia, które mają ułatwić życie. Takie bezwzględne i ponad rozsądkowe przestrzeganie zasad w programowaniu często kończy się straszną męczarnią. Owszem jest to na swój sposób piękne ale ... Gdybym chciał działać na polu abstrakcji to bym poszedł na matematykę zamiast informatykę:-)

1

Od OOP bym nie odchodził bo jednak ono jest dużo bliższe i bardziej naturalne podczas rozmów z "biznesem" a nawet innymi programistami, którzy jednak ciągle w większości myślą bardziej obiektowo niż funkcyjni.

No ja się nie zgadzam. OOP nadaje się IMO np. naturalnie do GUI, ale już typowa logika biznesowa np. w fintechach dla mnie jest o wiele bardziej naturalna z podejściem funkcyjnym. Szczególnie w tego typu aplikacjach docecnia się niemutowalność.

1

Wtrace jeszcze mala ciekawostke w kontekscie uzywania jezyka/paradygmatu, ktory najlepiej nada sie rozwiazania problemu nad ktorym pracujemy.

Mialem przyjemnosc przez chwile pracowac w jednej firmie z zespolem, ktory napisal wlasny jezyk i kompilator specjalnie pod domene w ktorej pracowal.
Na poczatku wydawalo mi sie to zupelnym overkillem. Dlaczego ktos w ogóle mialby to robic, mamy tyle jezykow ogolnego zastosowania, do wyboru do koloru mogloby sie wydawac. Rozne paradygmaty i ich miksologie. A jednak oni podjeli inna decyzje i z tego co pamietam bardzo byli zadowoleni z wyboru. Projekt oczywiscie byl mocno specyficzny i dotyczyl czegos z pudelka NLP.

0
<?php
_10: $i = 0;
_20: echo "Programowanie funkcyjne jest do doopy :-) \r\n";
_30: $i = $i + 1 ;
_40: if ( $i < 100 ) goto _20 ;

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