Nauka myślenia w języku Erlang

Odkurzyłem trochę moją umiejętność posługiwania się językiem Erlang poprzez rozwiązywanie problemów z Projektu Euler. Dotąd skupiałem się na jego wsparciu dla wymiany komunikatów, systemów rozproszonych czy też na wzorcach komunikacji (behaviours).

Doskwierała mi świadomość braku umiejętności pisania zgodnie z duchem tego języka. Uparcie chciałem przenieść moje doświadczenia z Java:

  • napisałem własnego eunit’a … takiego bardziej JUnit’owego,
  • ukrywałem odwołania do rekordów, których składnia wydawała mi się … nieczytelna
  • oszczędzałem na guardach w metodach,
  • ograniczałem list comprehension i higher-order functions by nie zaciemniać algorytmów,
  • rekurencja raczej przypominała pętle foreach w Java,
  • foldl, trzymanie danych w listach wydawało się … krępującą zaszłością.

Gdy zakres języków programowania ograniczał się do Java, C++, C#, Pascal wszystkie wydawały się podobne (w końcu należą do tej samej rodziny). W każdym stosuje się analogiczne podejścia (proceduralność lub obiektowość). Odmienność VBA i PHP spisywałem na karb specyficznych zastosowań tych języków.

Wystarczy, jednak poznanie czegoś diametralnie innego jak Erlang czy Scheme i świat przestaje być tak prosty 🙂 Przychodzi świadomość, że nowy język to nie zawsze tylko składnia + biblioteka standardowa + inne skróty klawiszowe w IDE. Czasem nowy język to zupełnie inny sposób myślenia.

Rozwiązywanie czysto algorytmicznych problemów z projektu Euler pozwoliło mi na eksperymenty z różnymi konstrukcjami Erlanga. Dzięki temu zaczynam wyrabiać sobie umiejętność programowania Erlangiem w Erlangu (a nie poprzestaję na używaniu Erlanga jak Java):

Guardy w metodach zaczynają mi się podobać:

is_prime(2) -> true;
is_prime(N) when N rem 2 =:= 0 -> false;
is_prime(N) -> is_prime(N, 3).

is_prime(N, Div) when N rem Div =:= 0 -> false;
is_prime(N, Div) when Div * Div > N -> true;
is_prime(N, Div)  -> is_prime(N, Div + 2).

Sposób wykorzystania metod ze standardowej biblioteki wydaje mi się coraz bardziej elegancki:

is_palindrom(N) ->
  Digits = integer_to_list(N),
  Digits =:= lists:reverse(Digits).

foldl? list comprehension? czemu nie:

multiply_digits(Int) ->
  IntAsString = integer_to_list(Int),
  ListOfDigits = [ Char - $0 || Char <- IntAsString],
  MultiplyFun = fun(X, Product) -> X * Product end,
  lists:foldl(MultiplyFun, 1, ListOfDigits).

Doceniam też, drobne ułatwienia jakie daje programiście środowisko, np. sposób obsługi liczb. Nie powinniśmy zawracać sobie głowy przełączaniem się na API obsługi dużych liczb – to niskopoziomowy szczegół implementacji a nie problem biznesowy:

TwoToPower1000 = math:pow(2, 1000),

(Tu chciałem wkleić fragment wykorzystujący higher order function w algorytmie sita Eratostenesa … ale zmieniłem ok 3 w nocy podejście w algorytmie i się nie zachował. Wiadomo jak to jest w nocy po kawie 🙂

Z niektórymi elementami nie przeszedłem jeszcze do porządku dziennego. Mogę zaakceptować, składnię testów:

-module(euler16_tests).
-include_lib("eunit/include/eunit.hrl").

should_sum_digits_in_power_of_2_test() ->
  26 = euler16:sum_of_digits_in_2_to_power(15).,

ale brak zielonego paska poprawiającego nastrój? Konieczność restartu Eclipse po niektórych czynnościach … Cóż może po prostu trzeba nauczyć się Emacs’a 🙂 Oprócz rozwiązywania problemów czysto matematycznych planuję:

… jak czas pozwoli 🙂

Advertisements
This entry was posted in Uncategorized and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s