Jak to wygląda, że w programowaniu funkcyjnym nie potrzebujemy wzorców projektowych

0

Hej. Jakiś czas temu przeżywając nieodwazejmnioną fascynację programowaniem funkcyjnym, trafiłem na jakieś porównanie, w którym jako jego zaletę prezentowaną możliwość zastąpienia wzorców projektowych taką metodyką.

Może po prostu mało widziałem. Robiłem chyba dwa podejścia do Haskella i na samym początku jakoś szło, ale potem już średnio. Najłatwiej byłoby mi to zjarzyć pewnie jakby ktoś mi pokazł porównanie dwóch programów na kilkanaście modułów gdzie jeden jest napisany obiektowo z użyciem wzorców, a drugi funkcyjnie, więc jeśli gdzieś coś takiego widzieliście, to byłbym wdzięczny. Albo może jednak ktoś uprzejmy opowie o tym tak, że jednak zrozumiem. :)

1

Haskell to ma jakieś swoje wzorce funkcyjne/kategorio-teoriowe/matematyczne.

4

Ehhh ktos prawdopodobnie uzyl zbyt duzego skrotu myslowego po prostu.

Dla przykladu wzorzec strategia: w OOP (w szczegolnosci np. w Javie przed erą lambd, ale lambdy to FP wlasnie) zeby to zrobic to trzeba bylo "przyhakowac" lekko, zeby zrobic klase implementujaca interfejs takiej strategii. W FP funkcje sa po prostu tzw. first-class-citizen i takie podejscie jest "naturalne". list.sortBy(elem => elem.width * elem.height) - zauwaz, ze argument podany do sortBy jest wlasnie czyms co przypomina wzorzec "strategia".

1

Jest tyle materiałów na ten temat, że jak się autorowi nie chce szukać w google ( https://fsharpforfunandprofit.com/fppatterns/ https://vimeo.com/113588389 polecam), to użyję bota - chociaż jego odpowiedź nie podoba mi się za bardzo :).

GPT-4

Oto przykład porównania podejścia funkcyjnego i obiektowego w kontekście wzorców projektowych, używając TypeScript jako języka przykładowego.

W programowaniu obiektowym, wzorce projektowe takie jak Strategy często wymagają tworzenia interfejsów i klas. Załóżmy, że mamy interfejs SortingStrategy z metodą sort, i kilka klas implementujących ten interfejs, takich jak QuickSort, MergeSort. Możesz następnie użyć wzorca Strategy w swojej klasie SortedList, która pozwala na wybór konkretnej strategii sortowania.

interface SortingStrategy {
    sort(data: number[]): number[];
}

class QuickSort implements SortingStrategy {
    sort(data: number[]): number[] {
        // Implementacja QuickSort
    }
}

class MergeSort implements SortingStrategy {
    sort(data: number[]): number[] {
        // Implementacja MergeSort
    }
}

class SortedList {
    private strategy: SortingStrategy;

    constructor(strategy: SortingStrategy) {
        this.strategy = strategy;
    }

    sort(data: number[]): number[] {
        return this.strategy.sort(data);
    }
}

W programowaniu funkcyjnym, ten sam problem można rozwiązać bardziej zwięźle, wykorzystując funkcje wyższego rzędu. Zamiast tworzyć klasy i interfejsy, definiujesz funkcje sortujące jako funkcje wyższego rzędu i bezpośrednio je przekazujesz.

const quickSort = (data: number[]): number[] => {
    // Implementacja QuickSort
};

const mergeSort = (data: number[]): number[] => {
    // Implementacja MergeSort
};

const sortList = (data: number[], sortingFunction: (data: number[]) => number[]): number[] => {
    return sortingFunction(data);
};

W tym podejściu funkcyjnym, możesz łatwo zmieniać strategie sortowania, przekazując różne funkcje jako argumenty. Jest to bardziej elastyczne i zwięzłe, ponieważ unika potrzeby tworzenia dodatkowych klas i interfejsów.

To porównanie pokazuje, jak programowanie funkcyjne może uprościć niektóre aspekty kodowania, które w programowaniu obiektowym wymagają stosowania wzorców projektowych.

0

Design pattern to nazwa na określoną klasę rozwiązań danego problemu.

In software engineering, a software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design. It is not a finished design that can be transformed directly into source or machine code. Rather, it is a description or template for how to solve a problem that can be used in many different situations.

A więc co do zasady pytanie jest troche malo sensowne, ale znając życie chodziło o patterny popularne w językach typu OOP - jakieś strategie, visitory itd itd. I czy w językach FP jest potrzeba stosowania ich? IIRC nie, bo np. visitora mozesz zastąpić switchem z exhaustive compile-time checkiem

8
  1. Jak napisano wyżej wiele patternów obiektowych (behavioralne) są w FP reprezentowane przez jeden prosty koncept -> funkcje wyższego rzędu, więc się o tych patternach nie mówi tak samo jak w językach imperatywnych. NIe będziemy się rozwodzić nad wzorcem podstaw wartość pod zmienną. Po prostu podstawowy sposób budowania programu. Choć czasem (rzadko) pożycza się terminologię z OOP i jak nie wiesz jak nazwać argument dla twojej funkcji to bywa, że nazwie się go strategy.

  2. Języki FP majã często mocno bardzo ekspresywną i rozbudowaną składnię, która powoduje, że jeśli jakiś wzorzec się powtarza to po prostu da się go ubrać w formie gotowej do użycia biblioteki/funkcji. (i nie powtarzać).
    Bywa, że ktoś powie, że Monada to jest wzorzec projektowy, bo za każdym razem jak pisze się monadę to klepie się kilka funkcji wg schematu... tyle, że ten schemat i funkcje są wydzielone jako TypeClass (to taki interfejs na sterydach) i działa to dokładnie jak implementowanie interfejsu w oop, nic nie trzeba opisywać diagramami, schematami i machaniem rękoma. (ok - tzw prawa trzeba wymachać rękami).

  3. Bywa, że czasem pojawi się schemat, którego jednak język nie wspiera i trzeba coś powtarzać (jak w klasycznych wzorcach projektowych), ale wtedy jakiś doktorant siada i dorzuca 197me rozszerzenie do haskella/ghc powodujące, że kolejna rzecz jest wbudowana w język i dalej robimy jak w punkcje 2. (podobnież w Scali - choć nie tak szaleńczo z tymi rozszerzeniami).

0

Oczywiście że są wzorce projektowe w programowaniu funkcyjnym, skąd pomysł że nie ma?

0

Wzorce projektowe to bardziej sprawa kulturowa niż praktyczna. Istnienie wzorców w OOP wyniką stąd, że ktoś kiedyś pisał książki na ten temat i tyle. Wzorce się przyjeły i dlatego są używane do nazywania pewnych wzorców w kodzie

FP tez operuje na wyższym poziomie tj. nie tworzy się interfejsu do każdej pierdoły tylko po prostu używa się funkcji. Możliwe, że wzorce są tak popularne, bo nazywanie tylu bezużytecznych klas jest trudne i potrzebujemy source of truth, które powie jak ma być

3
slsy napisał(a):

Wzorce projektowe to bardziej sprawa kulturowa niż praktyczna. Istnienie wzorców w OOP wyniką stąd, że ktoś kiedyś pisał książki na ten temat i tyle. Wzorce się przyjeły i dlatego są używane do nazywania pewnych wzorców w kodzie

A nie dlatego, że w danym paradygmacie często niektóre problemy się powtarzają, ergo powstały standardowe sposoby ich rozwiązywania?

2

https://kowainik.github.io/posts/haskell-mini-patterns
Katalog mini wzorców używanych w Haskellu

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