Pierwsze kroki z językiem programowania Elm
Opublikowany: 2022-03-11Kiedy główny deweloper bardzo interesującego i innowacyjnego projektu zasugerował przejście z AngularJS na Elm, moja pierwsza myśl brzmiała: Dlaczego?
Mieliśmy już ładnie napisaną aplikację AngularJS, która była w stanie stałym, dobrze przetestowana i sprawdzona w produkcji. A Angular 4, będący godnym ulepszeniem z AngularJS, mógł być naturalnym wyborem do przepisania — podobnie jak React lub Vue. Wiąz wydawał się dziwnym językiem specyficznym dla domeny, o którym ludzie prawie nie słyszeli.
Cóż, to było zanim dowiedziałem się cokolwiek o Elm. Teraz, z pewnym doświadczeniem, zwłaszcza po przejściu z AngularJS, myślę, że mogę odpowiedzieć na to „dlaczego”.
W tym artykule omówimy zalety i wady Elm oraz to, jak niektóre z jego egzotycznych koncepcji doskonale odpowiadają potrzebom front-endowego programisty. Aby uzyskać bardziej podobny do samouczka artykuł w języku Elm, możesz zapoznać się z tym wpisem na blogu.
Wiąz: czysto funkcjonalny język programowania
Jeśli jesteś przyzwyczajony do programowania w Javie lub JavaScript i czujesz, że jest to naturalny sposób pisania kodu, nauka Elm może być jak wpadnięcie do króliczej nory.
Pierwszą rzeczą, którą zauważysz, jest dziwna składnia: brak nawiasów klamrowych, mnóstwo strzałek i trójkątów.
Możesz nauczyć się żyć bez nawiasów klamrowych, ale jak definiujesz i zagnieżdżasz bloki kodu? Albo gdzie jest pętla for
lub jakakolwiek inna pętla, jeśli o to chodzi? Chociaż wyraźny zakres można zdefiniować za pomocą bloku let
, nie ma żadnych bloków w klasycznym sensie ani żadnych pętli.
Elm to czysto funkcjonalny, silnie typowany, reaktywny i sterowany zdarzeniami język klienta internetowego.
Możesz zacząć się zastanawiać, czy programowanie jest w ogóle możliwe w ten sposób.
W rzeczywistości te cechy składają się na niesamowity paradygmat programowania i tworzenia dobrego oprogramowania.
Czysto funkcjonalny
Możesz pomyśleć, że używając nowszej wersji Java lub ECMAScript 6, możesz wykonywać programowanie funkcjonalne. Ale to tylko powierzchowność.
W tych językach programowania nadal masz dostęp do arsenału konstrukcji językowych i pokusy uciekania się do jego niefunkcjonalnych części. Tam, gdzie naprawdę zauważasz różnicę, jest to, że nie możesz zrobić nic poza programowaniem funkcjonalnym. W tym momencie w końcu zaczynasz odczuwać, jak naturalne może być programowanie funkcjonalne.
W Elm prawie wszystko jest funkcją. Nazwa rekordu to funkcja, wartość typu unii to funkcja — każda funkcja składa się z funkcji częściowo zastosowanych do jej argumentów. Nawet operatory takie jak plus (+) i minus (-) są funkcjami.
Aby zadeklarować język programowania jako czysto funkcjonalny, a nie istnienie takich konstrukcji, brak wszystkiego innego ma ogromne znaczenie. Dopiero wtedy możesz zacząć myśleć w sposób czysto funkcjonalny.
Elm jest wzorowany na dojrzałych koncepcjach programowania funkcjonalnego i przypomina inne języki funkcjonalne, takie jak Haskell i OCaml.
Silnie napisane
Jeśli programujesz w Javie lub TypeScript, to wiesz, co to oznacza. Każda zmienna musi mieć dokładnie jeden typ.
Oczywiście istnieją pewne różnice. Podobnie jak w przypadku TypeScript, deklaracja typu jest opcjonalna. Jeśli nie jest obecny, zostanie wywnioskowany. Ale nie ma „żadnego” typu.
Java obsługuje typy generyczne, ale w lepszy sposób. Rodzaje w Javie zostały dodane później, więc typy nie są ogólne, chyba że określono inaczej. Aby z nich skorzystać, potrzebujemy brzydkiej składni <>
.
W Elm typy są ogólne, chyba że określono inaczej. Spójrzmy na przykład. Załóżmy, że potrzebujemy metody, która pobiera listę określonego typu i zwraca liczbę. W Javie byłoby to:
public static <T> int numFromList(List<T> list){ return list.size(); }
A w języku Elm:
numFromList list = List.length list
Chociaż opcjonalne, zdecydowanie sugeruję, aby zawsze dodawać deklaracje typu. Kompilator Elm nigdy nie zezwoli na operacje na niewłaściwych typach. Człowiekowi o wiele łatwiej popełnić taki błąd, zwłaszcza podczas nauki języka. Zatem powyższy program z adnotacjami typu będzie wyglądał następująco:
numFromList: List a -> Int numFromList list = List.length list
Na początku może wydawać się niezwykłe deklarowanie typów w osobnej linii, ale po pewnym czasie zaczyna to wyglądać naturalnie.
Język klienta internetowego
Oznacza to po prostu, że Elm kompiluje się do JavaScript, więc przeglądarki mogą go wykonać na stronie internetowej.
Biorąc to pod uwagę, nie jest to język ogólnego przeznaczenia, taki jak Java lub JavaScript z Node.js, ale język specyficzny dla domeny do pisania części klienckiej aplikacji internetowych. Co więcej, Elm zawiera zarówno pisanie logiki biznesowej (co robi JavaScript), jak i część prezentacyjną (co robi HTML) — wszystko w jednym języku funkcjonalnym.
Wszystko to jest zrobione w bardzo specyficzny, podobny do frameworka sposób, który nazywa się The Elm Architecture.
Reaktywny
Architektura Elm to reaktywna platforma internetowa. Wszelkie zmiany w modelach są renderowane natychmiast na stronie, bez wyraźnej manipulacji DOM.
W ten sposób jest podobny do Angulara czy Reacta. Ale Elm również robi to na swój sposób. Kluczem do zrozumienia jego podstaw jest podpis funkcji view
i update
:
view : Model -> Html Msg update : Msg -> Model -> Model
Widok Elm to nie tylko widok HTML modelu. Jest to HTML, który może generować wiadomości typu Msg
, gdzie Msg
jest dokładnie zdefiniowanym typem unii.
Dowolne zdarzenie na stronie standardowej może wygenerować komunikat. A po wygenerowaniu komunikatu Elm wewnętrznie wywołuje funkcję aktualizacji z tym komunikatem, która następnie aktualizuje model na podstawie komunikatu i bieżącego modelu, a zaktualizowany model jest ponownie wewnętrznie renderowany do widoku.
Oparte na wydarzeniach
Podobnie jak JavaScript, Elm jest sterowany zdarzeniami. Ale w przeciwieństwie na przykład do Node.js, gdzie poszczególne wywołania zwrotne są dostarczane dla akcji asynchronicznych, zdarzenia Elm są pogrupowane w dyskretne zestawy komunikatów, zdefiniowane w jednym typie komunikatu. I, jak w przypadku każdego typu unii, informacje, które niosą oddzielne wartości typu, mogą być dowolne.
Istnieją trzy źródła zdarzeń, które mogą generować komunikaty: akcje użytkownika w widoku Html
, wykonywanie poleceń i zdarzenia zewnętrzne, które subskrybowaliśmy. Dlatego wszystkie trzy typy, Html
, Cmd
i Sub
zawierają jako argument msg
. Ogólny typ msg
musi być taki sam we wszystkich trzech definicjach — ten sam, który został dostarczony do funkcji aktualizacji (w poprzednim przykładzie był to typ Msg
, przez duże M), w którym przetwarzanie wiadomości jest scentralizowane.
Kod źródłowy realistycznego przykładu
Możesz znaleźć kompletny przykład aplikacji internetowej Elm w tym repozytorium GitHub. Chociaż jest prosty, pokazuje większość funkcji używanych w codziennym programowaniu klienta: pobieranie danych z punktu końcowego REST, dekodowanie i kodowanie danych JSON, używanie widoków, komunikatów i innych struktur, komunikowanie się z JavaScript i wszystko, co jest potrzebne do kompilacji i pakowania Kod wiązu z Webpack.
Aplikacja wyświetla listę użytkowników pobranych z serwera.
Aby ułatwić proces instalacji/demo, serwer deweloperski Webpacka jest używany zarówno do pakowania wszystkiego, w tym Elm, jak i obsługi listy użytkownika.
Niektóre funkcje są w Elm, a niektóre w JavaScript. Robi się to celowo z jednego ważnego powodu: aby pokazać interoperacyjność. Prawdopodobnie chcesz wypróbować Elm, aby rozpocząć, lub stopniowo przełączać do niego istniejący kod JavaScript lub dodawać nową funkcjonalność w języku Elm. Dzięki interoperacyjności Twoja aplikacja nadal działa zarówno z kodem Elm, jak i JavaScript. Jest to prawdopodobnie lepsze podejście niż uruchamianie całej aplikacji od zera w Elm.
Część Elm w przykładowym kodzie jest najpierw inicjowana danymi konfiguracyjnymi z JavaScript, a następnie pobierana jest lista użytkowników i wyświetlana w języku Elm. Załóżmy, że mamy już zaimplementowane akcje użytkownika w JavaScript, więc wywołanie akcji użytkownika w Elm po prostu odsyła do niej wywołanie.
Kod wykorzystuje również niektóre koncepcje i techniki wyjaśnione w następnej sekcji.
Zastosowanie koncepcji wiązów
Przeanalizujmy niektóre egzotyczne koncepcje języka programowania Elm w rzeczywistych scenariuszach.
Typ Unii
To czyste złoto języka Wiązów. Pamiętasz te wszystkie sytuacje, kiedy trzeba było użyć strukturalnie różnych danych z tym samym algorytmem? Modelowanie takich sytuacji zawsze jest trudne.
Oto przykład: Wyobraź sobie, że tworzysz paginację swojej listy. Na końcu każdej strony powinny znajdować się linki do poprzedniej, następnej i wszystkich stron według ich numerów. Jak zorganizujesz go, aby zawierał informacje o tym, który link kliknął użytkownik?
Możemy użyć wielu wywołań zwrotnych dla poprzednich, następnych i numerów stron lub użyć jednego lub dwóch pól logicznych, aby wskazać, co zostało kliknięte, lub nadać specjalne znaczenie konkretnym wartościom całkowitym, takim jak liczby ujemne, zero itp. Ale żadne z te rozwiązania mogą modelować dokładnie tego rodzaju zdarzenie użytkownika.
W Elm to bardzo proste. Zdefiniowalibyśmy typ unii:
type NextPage = Prev | Next | ExactPage Int
Używamy go jako parametru dla jednej z wiadomości:
type Msg = ... | ChangePage NextPage
Na koniec aktualizujemy funkcję, aby mieć case
sprawdzającą typ nextPage
:
update msg model = case msg of ChangePage nextPage -> case nextPage of Prev -> ... Next -> ... ExactPage newPage -> ...
To sprawia, że rzeczy są bardzo eleganckie.
Tworzenie wielu funkcji mapy za pomocą <|
Wiele modułów zawiera funkcję map
z kilkoma wariantami, które można zastosować do różnej liczby argumentów. Na przykład List
zawiera map
, map2
, … , aż do map5
. Ale co, jeśli mamy funkcję, która przyjmuje sześć argumentów? Nie ma map6
. Ale jest technika, która to przezwycięży. Używa <|
funkcja jako parametr i funkcje częściowe, z niektórymi argumentami stosowanymi jako wyniki środkowe.
Dla uproszczenia załóżmy, że List
zawiera tylko map
i map2
, a my chcemy zastosować funkcję, która przyjmuje trzy argumenty na trzech listach.
Oto jak wygląda implementacja:
map3 foo list1 list2 list3 = let partialResult = List.map2 foo list1 list2 in List.map2 (<|) partialResult list3
Załóżmy, że chcemy użyć foo
, które po prostu mnoży swoje argumenty liczbowe, zdefiniowane w następujący sposób:
foo abc = a * b * c
Tak więc wynik map3 foo [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5]
to [1,8,27,64,125] : List number
.
Zdekonstruujmy, co się tutaj dzieje.
Po pierwsze, w partialResult = List.map2 foo list1 list2
, foo
jest częściowo stosowane do każdej pary z listy list1
i list2
. Wynikiem jest [foo 1 1, foo 2 2, foo 3 3, foo 4 4, foo 5 5]
, lista funkcji, która przyjmuje jeden parametr (ponieważ pierwsze dwa są już zastosowane) i zwraca liczbę.
Dalej w List.map2 (<|) partialResult list3
, jest to właściwie List.map2 (<|) [foo 1 1, foo 2 2, foo 3 3, foo 4 4, foo 5 5] list3
. Dla każdej pary tych dwóch list wywołujemy funkcję (<|)
. Na przykład dla pierwszej pary jest to (<|) (foo 1 1) 1
, czyli to samo co foo 1 1 <| 1
foo 1 1 <| 1
, czyli to samo co foo 1 1 1
, które daje 1
. Dla drugiego będzie to (<|) (foo 2 2) 2
, czyli foo 2 2 2
, co daje 8
, i tak dalej.
Ta metoda może być szczególnie przydatna w przypadku funkcji mapN
do dekodowania obiektów JSON z wieloma polami, ponieważ Json.Decode
udostępnia je do map8
.
Usuń wszystkie wartości nic z listy wartości możliwych
Załóżmy, że mamy listę wartości Maybe
i chcemy wyodrębnić tylko te wartości z elementów, które ją mają. Na przykład lista to:
list : List (Maybe Int) list = [ Just 1, Nothing, Just 3, Nothing, Nothing, Just 6, Just 7 ]
I chcemy uzyskać [1,3,6,7] : List Int
. Rozwiązaniem jest to jednowierszowe wyrażenie:

List.filterMap identity list
Zobaczmy, dlaczego to działa.
List.filterMap
oczekuje, że pierwszym argumentem będzie funkcja (a -> Maybe b)
, która jest stosowana na elementach dostarczonej listy (drugi argument), a wynikowa lista jest filtrowana, aby pominąć wszystkie wartości Nothing
, a następnie rzeczywistą wartości są pobierane z Maybe
s.
W naszym przypadku podaliśmy identity
, więc otrzymana lista to ponownie [ Just 1, Nothing, Just 3, Nothing, Nothing, Just 6, Just 7 ]
. Po przefiltrowaniu otrzymujemy [ Just 1, Just 3, Just 6, Just 7 ]
, a po wyodrębnieniu wartości jest to [1,3,6,7]
, tak jak chcieliśmy.
Niestandardowe dekodowanie JSON
Ponieważ nasze potrzeby w zakresie dekodowania (lub deserializacji) JSON zaczynają przekraczać to, co jest ujawnione w module Json.Decode
, możemy mieć problemy z tworzeniem nowych egzotycznych dekoderów. Dzieje się tak, ponieważ te dekodery są wywoływane w środku procesu dekodowania, np. w ramach metod Http
, i nie zawsze jest jasne, jakie są ich wejścia i wyjścia, zwłaszcza jeśli w dostarczonym JSON jest dużo pól.
Oto dwa przykłady pokazujące, jak postępować w takich przypadkach.
W pierwszym mamy dwa pola w przychodzącym JSON, a
i b
, oznaczające boki prostokątnego obszaru. Ale w obiekcie Elm chcemy przechowywać tylko jego powierzchnię.
import Json.Decode exposing (..) areaDecoder = map2 (*) (field "a" int) (field "b" int) result = decodeString areaDecoder """{ "a":7,"b":4 }""" -- Ok 28 : Result.Result String Int
Pola są indywidualnie dekodowane za pomocą dekodera field int
, a następnie obie wartości są dostarczane do podanej funkcji w map2
. Ponieważ mnożenie ( *
) jest również funkcją i przyjmuje dwa parametry, możemy go po prostu użyć w ten sposób. Wynikowy areaDecoder
to dekoder, który po zastosowaniu zwraca wynik funkcji, w tym przypadku a*b
.
W drugim przykładzie otrzymujemy niechlujne pole statusu, które może mieć wartość null lub dowolny ciąg, w tym pusty, ale wiemy, że operacja się powiodła tylko wtedy, gdy jest „OK”. W takim przypadku chcemy zapisać go jako True
, a we wszystkich innych przypadkach jako False
. Nasz dekoder wygląda tak:
okDecoder = nullable string |> andThen (\ms -> case ms of Nothing -> succeed False Just s -> if s == "OK" then succeed True else succeed False )
Zastosujmy to do niektórych plików JSON:
decodeString (field "status" okDecoder) """{ "a":7, "status":"OK" }""" -- Ok True decodeString (field "status" okDecoder) """{ "a":7, "status":"NOK" }""" -- Ok False decodeString (field "status" okDecoder) """{ "a":7, "status":null }""" -- Ok False
Klucz tutaj znajduje się w funkcji dostarczonej do andThen
, która pobiera wynik poprzedniego dekodera łańcucha znaków dopuszczającego wartość null (który jest Maybe String
), przekształca go w to, czego potrzebujemy i zwraca wynik jako dekoder z pomocą succeed
.
Zabrany klucz
Jak widać z tych przykładów, programowanie w sposób funkcjonalny może nie być zbyt intuicyjne dla programistów Java i JavaScript. Przyzwyczajenie się do tego zajmuje trochę czasu, z wieloma próbami i błędami. Aby pomóc to zrozumieć, możesz użyć elm-repl
do ćwiczenia i sprawdzania typów zwracanych wyrażeń.
Przykładowy projekt, do którego link znajduje się wcześniej w tym artykule, zawiera kilka dodatkowych przykładów niestandardowych dekoderów i koderów, które mogą również pomóc w ich zrozumieniu.
Ale dlaczego warto wybrać Elm?
Będąc tak różnym od innych frameworków klienckich, język Elm z pewnością nie jest „kolejną biblioteką JavaScript”. Jako taki ma wiele cech, które w porównaniu z nimi można uznać za pozytywne lub negatywne.
Zacznijmy najpierw od strony pozytywnej.
Programowanie klienta bez HTML i JavaScript
Wreszcie masz język, w którym możesz to wszystko zrobić. Koniec z separacją i niezręcznymi kombinacjami ich mieszania. Bez generowania HTML w JavaScript i bez niestandardowych języków szablonów z pewnymi uproszczonymi regułami logiki.
Dzięki Elm masz tylko jedną składnię i jeden język w pełnej krasie.
Jednolitość
Ponieważ prawie wszystkie koncepcje opierają się na funkcjach i kilku strukturach, składnia jest bardzo zwięzła. Nie musisz się martwić, czy jakaś metoda jest zdefiniowana na poziomie instancji lub klasy, czy jest to tylko funkcja. Są to wszystkie funkcje zdefiniowane na poziomie modułu. I nie ma stu różnych sposobów iteracji list.
W większości języków zawsze pojawia się spór o to, czy kod jest napisany na sposób języka. Wiele idiomów trzeba opanować.
W Elm, jeśli się kompiluje, prawdopodobnie jest to sposób „Elm”. Jeśli nie, cóż, na pewno nie.
Wyrazistość
Chociaż zwięzła, składnia Elm jest bardzo wyrazista.
Osiąga się to głównie poprzez użycie typów unii, formalnych deklaracji typów i stylu funkcjonalnego. Wszystko to inspiruje do korzystania z mniejszych funkcji. Na końcu otrzymujesz kod, który jest w dużej mierze samodokumentujący.
Brak wartości null
Kiedy używasz Javy lub JavaScript przez bardzo długi czas, null
staje się dla Ciebie czymś całkowicie naturalnym — nieuniknioną częścią programowania. I chociaż ciągle widzimy NullPointerException
i różne typy błędów TypeError
, nadal nie uważamy, że prawdziwym problemem jest istnienie null
. To takie naturalne .
Szybko staje się jasne po pewnym czasie z Wiązem. Brak null
nie tylko zwalnia nas z ciągłego obserwowania błędów odwołań do wartości null w czasie wykonywania, ale także pomaga nam pisać lepszy kod poprzez jasne definiowanie i obsługę wszystkich sytuacji, w których możemy nie mieć rzeczywistej wartości, a tym samym zmniejszamy dług techniczny poprzez nie odkładanie null
obsługi, aż coś się zepsuje.
Pewność, że to zadziała
Tworzenie poprawnych składniowo programów JavaScript można wykonać bardzo szybko. Ale czy to faktycznie zadziała? Cóż, zobaczmy po ponownym załadowaniu strony i dokładnym przetestowaniu.
Z Wiązem jest odwrotnie. W przypadku statycznego sprawdzania typu i wymuszonego sprawdzania null
, kompilacja potrzebuje trochę czasu, zwłaszcza gdy początkujący pisze program. Ale po skompilowaniu jest duża szansa, że będzie działać poprawnie.
Szybko
Może to być ważnym czynnikiem przy wyborze frameworka klienta. Reakcja rozbudowanej aplikacji internetowej jest często kluczowa dla doświadczenia użytkownika, a tym samym sukcesu całego produktu. A jak pokazują testy, Elm jest bardzo szybki.
Plusy Elm vs Tradycyjne Frameworki
Większość tradycyjnych frameworków internetowych oferuje zaawansowane narzędzia do tworzenia aplikacji internetowych. Ale ta moc ma swoją cenę: zbyt skomplikowana architektura z mnóstwem różnych koncepcji i zasad dotyczących tego, jak i kiedy ich używać. Opanowanie tego wszystkiego zajmuje dużo czasu. Istnieją kontrolery, komponenty i dyrektywy. Następnie są fazy kompilacji i konfiguracji oraz faza uruchamiania. Do tego dochodzą usługi, fabryki i wszystkie niestandardowe języki szablonów używane w dostarczonych dyrektywach — wszystkie te sytuacje, w których musimy bezpośrednio wywołać $scope.$apply()
w celu odświeżenia strony i nie tylko.
Kompilacja Elm do JavaScript jest z pewnością również bardzo skomplikowana, ale programista jest chroniony przed koniecznością poznania wszystkich śrub i nakrętek. Po prostu napisz Elm i pozwól kompilatorowi wykonać swoją pracę.
A dlaczego nie wybrać wiązu?
Dość wychwalania Wiązu. Zobaczmy teraz niektóre z jego niezbyt wspaniałych stron.
Dokumentacja
To naprawdę poważny problem. W języku Elm brakuje szczegółowej instrukcji.
Oficjalne samouczki po prostu przeglądają język i pozostawiają wiele pytań bez odpowiedzi.
Oficjalne odniesienie do API jest jeszcze gorsze. Wiele funkcji nie ma żadnego wyjaśnienia ani przykładów. I są też tacy, którzy mają zdanie: „Jeśli to jest mylące, przejdź przez samouczek architektury Elm. To naprawdę pomaga!” Nie jest to najlepsza linia, jaką chcesz zobaczyć w oficjalnych dokumentach API.
Miejmy nadzieję, że wkrótce się to zmieni.
Nie wierzę, że Elm może być szeroko zaadoptowany z tak ubogą dokumentacją, zwłaszcza z ludźmi wywodzącymi się z Javy lub JavaScript, gdzie takie koncepcje i funkcje nie są w ogóle intuicyjne. Aby je zrozumieć, potrzebna jest znacznie lepsza dokumentacja z wieloma przykładami.
Format i białe znaki
Pozbycie się nawiasów klamrowych lub nawiasów i użycie białego miejsca do wcięcia może wyglądać ładnie. Na przykład kod Pythona wygląda bardzo schludnie. Ale dla twórców elm-format
to nie wystarczyło.
Przy wszystkich podwójnych odstępach linii oraz wyrażeniach i przypisaniach podzielonych na wiele linii, kod Elm wygląda bardziej pionowo niż poziomo. To, co byłoby jednym wierszem w starym dobrym C, może z łatwością rozciągać się na więcej niż jeden ekran w języku Elm.
Może to brzmieć dobrze, jeśli płacisz za napisane wiersze kodu. Jeśli jednak chcesz dopasować coś do wyrażenia rozpoczętego 150 wierszy wcześniej, powodzenia w znalezieniu odpowiedniego wcięcia.
Obsługa rekordów
Trudno z nimi pracować. Składnia do modyfikowania pola rekordu jest brzydka. Nie ma łatwego sposobu na modyfikowanie pól zagnieżdżonych lub odwoływanie się do pól według nazwy. A jeśli używasz funkcji akcesorów w sposób ogólny, jest wiele problemów z prawidłowym pisaniem.
W JavaScript rekord lub obiekt to centralna struktura, którą można konstruować, uzyskiwać do niej dostęp i modyfikować na wiele sposobów. Nawet JSON to tylko serializowana wersja rekordu. Programiści są przyzwyczajeni do pracy z rekordami w programowaniu internetowym, więc trudności w ich obsłudze w Elm mogą stać się zauważalne, jeśli zostaną użyte jako podstawowa struktura danych.
Więcej pisania
Elm wymaga napisania więcej kodu niż JavaScript.
Nie ma niejawnej konwersji typu dla operacji na ciągach i liczbach, więc potrzebnych jest wiele konwersji typu int-float, a zwłaszcza wywołania toString
, które następnie wymagają nawiasów lub symboli aplikacji funkcji, aby pasowały do poprawnej liczby argumentów. Ponadto funkcja Html.text
wymaga ciągu jako argumentu. Potrzebnych jest wiele wyrażeń przypadku, dla wszystkich tych Maybe
s, Results
, typów itp.
Głównym tego powodem jest ścisły system typów, który może być uczciwą ceną do zapłacenia.
Dekodery i kodery JSON
Jednym z obszarów, w którym bardziej wyróżnia się typowanie, jest obsługa JSON. To, co jest po prostu wywołaniem JSON.parse()
w JavaScript, może obejmować setki wierszy w języku Elm.
Oczywiście potrzebny jest jakiś rodzaj mapowania między strukturami JSON i Elm. Ale potrzeba napisania zarówno dekoderów, jak i enkoderów dla tego samego fragmentu JSON to poważny problem. Jeśli Twoje interfejsy API REST przesyłają obiekty z setkami pól, będzie to dużo pracy.
Zakończyć
Widzieliśmy o Elm, czas odpowiedzieć na znane pytania, prawdopodobnie tak stare jak same języki programowania: Czy jest lepszy od konkurencji? Czy powinniśmy go używać w naszym projekcie?
Odpowiedź na pierwsze pytanie może być subiektywna, bo nie każde narzędzie to młotek i nie wszystko to gwóźdź. Elm może błyszczeć i być lepszym wyborem w porównaniu z innymi frameworkami klienta internetowego w wielu przypadkach, podczas gdy w innych nie spełnia oczekiwań. Ale oferuje naprawdę wyjątkową wartość, która może sprawić, że tworzenie frontonu internetowego będzie o wiele bezpieczniejsze i łatwiejsze niż alternatywy.
Na drugie pytanie, aby uniknąć odpowiedzi z odwiecznym „to zależy”, prosta odpowiedź brzmi: Tak. Nawet przy wszystkich wspomnianych wadach, sama pewność, że Elm daje ci, że twój program jest poprawny, jest wystarczającym powodem, aby go użyć.
Kodowanie w Elm to także świetna zabawa. To zupełnie nowa perspektywa dla każdego, kto jest przyzwyczajony do „konwencjonalnych” paradygmatów programowania internetowego.
W prawdziwym użytkowaniu nie musisz natychmiast przełączać całej aplikacji na Elm lub całkowicie w niej uruchamiać nowej. Możesz wykorzystać jego współdziałanie z JavaScriptem, aby spróbować, zaczynając od części interfejsu lub niektórych funkcji napisanych w języku Elm. Szybko przekonasz się, czy odpowiada on Twoim potrzebom, a następnie poszerzysz jego zastosowanie lub go opuścisz. A kto wie, możesz również zakochać się w świecie funkcjonalnego programowania internetowego.