Wątek przeniesiony 2021-03-22 10:23 z Nietuzinkowe tematy przez cerrato.

Programowanie funkcyjne - Haskell, Lisp etc.

1

O co ten cały szum z programowanie funkcyjnym? Dla mnie naturalne rozumienie komputera to programowanie imperatywne (chyba że deklaratywny SQL). Rozumiem, że są przydatne elementy programowania funkcyjnego w JavaScript czy Javie. W korporacjach można też stosować różne immutable struktury. Ale jakie jest zastosowanie języków prawdziwie funkcyjnych jak Haskell czy Lisp w realnej gospodarce? Czy są to języki od dziesięcioleci wyłącznie badawcze na uczelniach, formalizmy matematyczne do rozwiązywania prostych zagadek, czy mają albo mogą mieć w przyszłości jakieś praktyczne zastosowanie?

0

2

Nie znam sie, ale wypowiem. Niektóre algorytmy są bardzo wygodne implementacji w językach funkcyjnych. Generalnie algorytmy rekurencyjne bardzo fajnie się pisze funkcyjnie. a potem np można stosować elementy z f# w c# co też jest bardzo spoko.

2

Powiem wam tylko tyle że podczas kompilacji kod Haskella przekształcany jest do języka C. W kolejnej fazie kompilator C tworzy plik wynikowy. Wydaje się wam, że to Haskell a to jest specjalna wersja języka C...

6
randomowy napisał(a):

Dla mnie naturalne rozumienie komputera to programowanie imperatywne (chyba że deklaratywny SQL).

Tylko tak Ci się wydaje, bo nauka programowania u każdej znanej mi osoby zaczyna się od programowania imperatywnego. To, że potrafisz tak rozumować nie znaczy, że jest to naturalne - po prostu masz z tym większe doświadczenie. Imperatywność jest naturalna dla maszyny, nie dla człowieka.

ple napisał(a):

Powiem wam tylko tyle że podczas kompilacji kod Haskella przekształcany jest do języka C. W kolejnej fazie kompilator C tworzy plik wynikowy. Wydaje się wam, że to Haskell a to jest specjalna wersja języka C...

XD A C to specjalna wersja asemblera, podobnie jak większość języków.

3

Programując funkcyjnie łatwo utrzymać porządek w kodzie. Jak masz czystą funkcję, łatwiej jest określić czy jest poprawna czy nie. Poza tym, ułatwia to zrównoleglanie kodu.

3

Serwis lichess.org jest napisany w Scali i działa wybornie w porównaniu z chess.com, który jest napisany w cholera-wie-czym, więc domniemuję, że w funkcyjności jest jakaś wartość dodana. Natomiast należy wiedzieć kiedy warto a kiedy nie warto stosować.

Programy funkcyjne łatwiej się analizuje, bo masz tak jakby jeden wymiar mniej - nie jest istotna kolejność wykonania operacji, a jedynie ich wzajemne zależności. Zrównoleglanie też zwykle przychodzi łatwiej. Natomiast z drugiej strony trudniej o dobrą wydajność (w sensie wydajności z jednego rdzenia). Struktury niemutowalne zwykle wprowadzają znaczny narzut w porównaniu z odpowiednikami mutowalnymi.

1

Programowanie funkcyjne nadaje pewne właściwości funkcją, skopiuje je z książki dla ułatwienia:
They are idempotent
They offer referential transparency
They are memoizable
They can be lazy
They’re easier to reason about
They’re easier to combine
They’re easier to test
They’re easier to debug
They’re easier to parallelize

Skoro funkcja X nie zapisuje stanów wewnętrznych i nie odczytuje ich (np zmienna klasy, funkcja rand(), odczytywanie z pliku) oznacza to, że wynik funkcji X będzie zawsze taki sam. Bo polega ona tylko na swoim wewnętrznym stanie. Dzięki temu zachodzi np. właściwość referential transparency

Skoro funkcja X nie zapisuje stanów wewnętrznych i nie odczytuje ich, oznacza to, że nie mamy powodu wywoływania ją póki nie będziemy potrzebować jej wyniku, więc zróbmy ją lazy

Skoro funkcja X nie zapisuje stanów wewnętrznych i nie odczytuje ich, oznacza to, że nie da się napisać tak funkcji, żeby miała sens i zwracała void, tzn

void func(String s) {
 //wpisz coś do tej funkcji sensownego, że nie zapisuje stanów wewnętrznych i nie odczytuje ich, ale ktoś nadal będzie potrzebował tej funkcji (funkcje haczyki się nie liczą)
}

nie ma takiej funkcji, oznacza to, że wystarczy przetestować co funkcja zwraca (czy to testy manualne czy jednostkowe). Dodatkowo, takie testy jednostkowe będą nastawione na zwracany stan nie behawioralność funkcji

ITP ITD

1

W przeszłości były podejmowane próby komercjalizacji e.g. https://en.wikipedia.org/wiki/Lisp_machine, jak widzisz nie bardzo to wypaliło.

Osobiście uważam że języki czysto funkcyjne (zwłaszcza Haskell) są tworzone przez oszołomów matematyków, dla których czytelność kodu czy cała otoczka inżynieryjna projektu (unit testy, benchmarki, system build'u i zarządzania zależnościami, IDE, debuggery, lintery itp). nie istnieje. Jeżeli już takie języki miały by gdzieś znaleźć zastosowanie to raczej w firmach typu Google, ale te w przekorny sposób stawiają na sprawdzone w boju technologie typu Java i C++ (a ostatnio także Go). Facebook używał Ocamla do tworzenia kompilatorów swojego Hack'a ale to też bardziej sfera badań i rozwoju.

Nota bene warto również zauważyć ze czysto obiektowe języki typu Smalltalk również się nie przyjęły. W przypadku SmallTalk'a powód był podobny, zapomniano o współpracy z istniejącymi bibliotekami, kod nie był traktowany jako tekst (Class Browser), deployment był dziwny (trzeba było wgrywać obraz maszyny wirtualnej SmallTalka).

Z drugiej strony "brzydkie" języki programowania, które nie mają oporów przed dodawaniem pragmatycznych funkcjonalności jak JS, Java i C++ mają się bardzo dobrze...

W sumie dla mnie jedyny "czysto" funkcyjny język który ma jako takie szanse na szerszą adopcję to F# (Scala to raczej chimera FP i OOP).

PS. Warto jeszcze popatrzeć na zmianę języka z punktu widzenia biznesu. Dawno dawno temu przejście assembler -> prog. strukturalne dawało olbrzymie zyski z produktywności i spadek liczby błędów. Potem nastąpiła długa era panowania C i Pascala aż w końcu dotarliśmy do ściany o nazwie duże projekty z olbrzymią (jak na tamte czasy) liczbą programistów i linii kodu. C bez przestrzeni nazw, paczek itp. nie pozwalał w wydajny sposób zarządzać dużymi bazami kodu. I tak na scenę wtoczył się C++ zapewniając właśnie to, ładne grupowanie metod w obiekty. Rozszerzało to znacznie przestrzeń nazw bo teraz 100 obiektów mogło mieć metodę add i nie było żadnych konfliktów. Potem projekty nadal rosły, na scenie pojawił się internet - jest to moment wzrostu znaczenia języków skryptowych takich jak Perl i potem PHP które oferowały dużą produktywność w pracy z siecią Web. Moment ten wykorzystała też Java, rozwiązując po stronie backendu problemy C++ - to jest brak biblioteki standardowej + GC.
FF 20 lat i jesteśmy w 2021, czy istnieje obecnie język FP który ma killer feature? Wydaje mi się że nie. Kilka lat temu wydawało się że takim killer feature'em będzie programowanie równoległe ale zarówno C# jak i Java rozwiązały ten problem za pomocą bibliotek (do tego doszło programowanie reaktywne).

Powyższe rozumownie wyjaśnia też dlaczego np. Kotlin ma takie trudności z adopcją. Biznes nie zmieni języka tylko dlatego żeby programistom się lepiej pisało (a przynajmniej nie do czas aż Ci masowo zaczną składać wypowiedzenia lub będzie bardzo duży problem z rekrutacją nowych ludzi). Żeby nastąpił zmiana nowy język musi dostarczać czego co zagwarantuje olbrzymi wzrost produktywności. Ostatnią taką rzeczą była chmura. Można się zastanowić czy w językach programowania taki wzrost jest jeszcze w ogóle możliwy?

2
randomowy napisał(a):

O co ten cały szum z programowanie funkcyjnym? Dla mnie...

Dla ciebie może i tak, dla coraz większej liczby osób nie.

Ale jakie jest zastosowanie języków prawdziwie funkcyjnych jak Haskell czy Lisp w realnej gospodarce?

Nie wiem jak z Haskellem czy LISPem, ale modele event-based (czyli bardzo duża część gospodarki, od czujników zaczynając) są czymś naturalnym dla programowania funkcyjnego, natomiast w modelu imperatywnym trzeba tworzyć różne dziwne fikołki.

7

To może kilka wyjaśnień.

Haskell już od kilku lat nie jest językiem akademickim tylko wlazł do biznesu - nawet do mnie docierają oferty pracy w Haskellu - Polska (Warszawa) lub Zurich głównie.
Scala funkcyjna jest już w biznesie od dawna - można nawet powiedzieć, że przetarła szlaki Haskellowi trochę - otworzyła oczy niedowiarkom.

Dlaczego:
Głównie dlatego, żeby wbrew wszelkim przesądom móc o 15:55 w piątek puścić release na produkcje i spokojnie jechać na narty - nie patrząc nawet na to co leci w konsoli.
Kod funkcyjny, wsparty typami powoduje, że wiele błędów nawet nie da się popełnić (albo trzeba się postarać). Jak się skompiluje to musi działać.
Testów trzeba pisać dużo mniej, bo testujemy zasady biznesowe, a nie czy wszystko razem do kupy działa.

Czyste funkcje się zajebiście i bezproblemowo komponują.
Dla takich staruchow jak ja, którym się nie chce wysilać przy każdej linijce kodu - co też tu moze pójść nie tak - fp jest idealne - kompilator się wysila i robi mi review.
Killer feature fp to właśnie komponowalność, a w związku z tym bezpieczeństwo.

FP przyjęło sie w finansach, blockchain itp. - wszędzie tam, gdzie drobna pomyłka i masowo przelewamy pieniądze nie tym ludziom co trzeba, albo masowo kupujemy po nie tej co trzeba cenie.

Obecnie, co prawda większość kodu piszę w kotlinie, wbrew temu co napisano kotlin nie ma problemu z adaptacją wygryza javę nawet w korporacjach (oczywiście na pewno nie wszędzie), ale przynajmniej piszę funkcyjnie w tym kotlinie (Scala--) (dorobiłem nawet plugin do lintera, który czystość sprawdza).

1

FP przyjęło sie w finansach, blockchain (...)

Rzut okiem na Solidity pokazuje że tego funkcyjnego podejścia tam jednak brakuje: https://docs.soliditylang.org/en/v0.4.21/control-structures.html#scoping-and-declarations

Sam bitcoin naklepany w C++ (no jak oni mogli!): https://github.com/bitcoin/bitcoin a ETH w Go: https://github.com/ethereum/go-ethereum

Z ciekawości NoFluffJobs:

Ofert w Scali jest nieco więcej ale większość to nie programowanie tylko big data. Co ciekawe stawki na stanowiska dla Scalowców (nie big data) mizerne (przykłada od SM: https://nofluffjobs.com/pl/job/mid-java-scala-developer-softwaremill-remote-apn7hgqc widły 11k - 17k, bez szału choć język znacznie bardziej trudny i wymagający). Pokazuje to jak biznes szanuje programowanie funkcyjne.

W erlangu jest nico ciekawiej (https://nofluffjobs.com/pl/jobs?criteria=erlang), w sumie ta oferta od blockfi nawet przykuła moją uwagę. Niemniej widać że funkcyjniaki to < 10% rynku.

0
0xmarcin napisał(a):

FP przyjęło sie w finansach, blockchain (...)

Rzut okiem na Solidity pokazuje że tego funkcyjnego podejścia tam jednak brakuje: https://docs.soliditylang.org/en/v0.4.21/control-structures.html#scoping-and-declarations

DAML się ładnie wpasowuje https://daml.com/

https://www.juspay.in/ to jeden z większych graczy w temacie fp.

Generalnie szukanie takiego stosu w pl mija się z celem.

1

Świetnie, że wytrzasnąłes solidity, ale czego to dowodzi? Czy to nie w solidity ktoś się kiedyś rypnął i stąd mamy split w Ethereum?
Jest również ileś funkcyjnych w okolicy smart contracts - ostatnio obiłem się o daml.

https://github.com/digital-asset/ex-bond-issuance/blob/master/src/main/daml/DA/RefApps/Bond/Redemption.daml

Co do stawek to pełna racja - obecnię pracuje z dodatkiem za szkodliwe warunki pracy (czyli okazyjne potykanie się o javę i imperatywnego kotlina).

Paradoksalnie jeszcze grzebie czasem w TS, który jeśli się używa Reacta to potrafi być zupełnie czysto funkcyjny i nawet przyjemny.

Oferty na Haskell czy Scala są faktycznie słabsze, więcej dobrych ludzi chce w tym pracować i godzi się na niższe pensje (jak trafię kiedyś jeszcze na dłużej do jakiegoś Springa lub czegoś podobnego to też taki krok przemyśle).

2

Struktury niemutowalne zwykle wprowadzają znaczny narzut w porównaniu z odpowiednikami mutowalnymi.

@Krolik Niby tak, ale w praktyce:

  1. Kolekcje w kodzie biznesowym sa małe
  2. Często i tak list, tablic etc nie zmieniasz. Np. jak ładujesz 20 pierwszych operacji z histori karty to będziesz dalej przepychał te 20 operacji do frontendu czy jakiegoś SOAPA ;)
  3. Można stosować lokalne mutowanie, nawet "ukryte". Np. jak masz Collector w Javie który tworzy kolekcję ze strumienia to możesz stosować lokalnie mutowalny buildier ArrayList a zwróci Ci niemutowalną kolekcję
  4. W praktyce największym kosztem są operacje IO, głównie bazodanowe i nieumiejętne stosowanie albo po prostu stosowanie ORM i np. wczytanie całych encji mimo że potrzebujesz 3 pól z 20, albo N+1.
    Dodatkowo refleksja o którą oparte są runtimowe frameworki też jest kosztowna pod wzlędem czasu.
5

No FP ma trochę zastosowań:

  • Lispy
    • gamedev (Naughty Dog)
    • webdev (kiedyś Reddit, Hacker News)
    • grafika/projektowanie (AutoCAD, GIMP)
    • sysops (Puppet, Guix)
    • testowanie (Jepsen)
  • BEAM (Erlang, Elixir i ferajna)
    • komunikacja (ejabberd, Discord, WhatsApp)
    • e-commerce (PepsiCo, Klarna)
    • hazard (bet365)
    • bazy danych (RabbitMQ, Mnesia, Riak, CouchDB, BarrelDB)
    • testowanie (QuviQ QuickCheck)
    • telco (Ericsson, Cisco)
  • ML
    • dowodzenie i weryfikacja (Coq, Isabelle)
    • generowanie kodu (FFTW)
    • implementacja języków (Coq, Haxe, Hack, ReasonML)
    • analiza statyczna programów (Infer, Frama-C, Flow)
  • Haskell
    • parsery (Pandoc, Corrode)
    • statyczna analiza (ShellCheck)
    • systemy kontroli wersji (git-annex, Darcs)
    • webdev (PostgREST)
2

Ja to widzę tak. Języki funkcyjne w pewnym sensie przydeptują swój własny wąż z tlenem.
Ich problem polega właśnie na tym, że ich zalety są doceniane. O co chodzi?
Współczesne języki głównego nurtu są w dużym stopniu hybrydowe.
To znaczy - w wielu już teraz popularnych językach można sobie pisać w miarę funkcyjnie (Scala, Kotlin, C#). I ten trend raczej się nasila, niż słabnie.

No to po co ktoś ma przestawiać się na język silniej związany z nurtem FP - jak na przykład F# - skoro co lepsze kąski i tak wpadną mu do C#?

Purystom to oczywiście nie wystarczy, ale purystów zawsze jest mało.

2

To znaczy - w wielu już teraz popularnych językach można sobie pisać w miarę funkcyjnie (Scala, Kotlin, C#). I ten trend raczej się nasila, niż słabnie.

Ty chyba nie wiesz co to FP jesli wymieniasz tutaj C#.

Podpowiem: FP nie polega na pisaniu lambd.

EDIT: to znaczy nie jest to warunek wystarczajacy ani nawet konieczny * ;)

0
V-2 napisał(a):

Ich problem polega właśnie na tym, że ich zalety są doceniane. O co chodzi?
Współczesne języki głównego nurtu są w dużym stopniu hybrydowe.

Ludzie po prostu odkryli na nowo, że w oop też możesz mieć lambdy. Właściwie zatoczyliśmy koło smalltalk -> java -> statycznie typowany smalltalk.

No to po co ktoś ma przestawiać się na język silniej związany z nurtem FP - jak na przykład F# - skoro co lepsze kąski i tak wpadną mu do C#?

Na F# po nic, bo akurat w nim programowanie obiektowe jest jedyną opcją. Nie ma funktorów z ocamla, nie ma type classes, nie ma nic... Już C++ ma więcej możliwości do budowania funkcyjnych abstrakcji.

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