2010-05-04 14 views
6

Używam Erlanga przez ostatnie osiem godzin, a ja spędziłem dwa z tych, którzy walą głową w klawiaturę, próbując odgadnąć błąd wyjątku, który moja konsola powraca.Błąd wyjątku w Erlang

Piszę program do gry w kości, aby nauczyć się erlang. Chcę, żeby mógł zadzwonić z konsoli przez tłumacza erlang. Program akceptuje liczbę kości i ma generować listę wartości. Każda wartość ma wynosić od jednego do sześciu.

Nie będę was zanudzać dziesiątkami pojedynczych mikro-zmian, które zrobiłem, aby spróbować rozwiązać problem (przypadkowa inżynieria), ale opublikuję mój kod i błąd.

Źródło:

-module(dice2). 
-export([d6/1]). 

d6(1) -> 
    random:uniform(6); 
d6(Numdice) -> 
    Result = [], 
    d6(Numdice, [Result]). 

d6(0, [Finalresult]) -> 
    {ok, [Finalresult]}; 

d6(Numdice, [Result]) -> 
    d6(Numdice - 1, [random:uniform(6) | Result]). 

Kiedy uruchomić program z mojego konsoli jak tak ... dice2:d6(1).

... mam losową liczbę od jednego do sześciu jak oczekiwano . Jednak kiedy uruchomić tę samą funkcję z dowolnej liczby wyższej niż jeden jako argument pojawia się następujący wyjątek ...

**exception error: no function clause matching dice2:d6(1, [4|3])

... Wiem II nie mają funkcji z pasującymi argumentów ale don Umie napisać funkcję ze zmiennymi argumentami i zmienną z argumentów.

Próbowałem modyfikowania funkcji w pytaniu jak tak ....

d6(Numdice, [Result]) -> 
    Newresult = [random:uniform(6) | Result], 
    d6(Numdice - 1, Newresult). 

... ale mam w zasadzie ten sam błąd. Czy ktoś wie, co się tutaj dzieje?

Odpowiedz

6

Jest to w zasadzie błąd typu. Gdy Result jest listą, [Result] jest listą z jednym elementem. Np. Jeśli twoja funkcja działała, zawsze zwracałaby listę z jednym elementem: Finalresult.

To co się dzieje (używając ==> dla „zmniejsza się”):

d6(2) ==> %% Result == [] 
d6(2, [[]]) ==> %% Result == [], let's say random:uniform(6) gives us 3 
d6(1, [3]) ==> %% Result == 3, let's say random:uniform(6) gives us 4 
d6(0, [4|3]) ==> %% fails, since [Result] can only match one-element lists 

Przypuszczalnie nie chcesz [[]] w pierwszej rozmowy, a nie chcesz Result być 3 W trzecie połączenie. Tak to powinno go naprawić:

d6(Numdice) -> Result = [], d6(Numdice, Result). %% or just d6(Numdice, []). 

d6(0, Finalresult) -> {ok, Finalresult}; 
d6(Numdice, Result) -> d6(Numdice - 1, [random:uniform(6) | Result]). 

Lekcja: jeśli język jest dynamicznie wpisane, to nie oznacza, że ​​można uniknąć typy poprawne. Wręcz przeciwnie, oznacza to, że kompilator nie pomoże ci w tym, jak to tylko możliwe.

+1

Twoje rozwiązanie działało pięknie i pomogło mi zrozumieć mój błąd. Jestem nowy w paradygmacie funkcjonalnym, więc jest dużo do pochłonięcia. Gdzie byłem zdezorientowany myślałem przez wywołanie d6 (Numdice, Wynik) z pustą listą, każda nowa rozmowa zakończyłaby się tylko możliwością dopasowania do pustej listy jako jednym z parametrów do d6, ponieważ nie można ponownie powiązać zmienne w zakresie. Zgaduję, że zapomniałem o wiążących zasadach obowiązujących tylko w ramach danej funkcji * przed * następnym połączeniem [przewija oczami]. Zaplątałem się w odpowiedni problem i zapomniałem o długości elementu. W każdym razie, dziękuję za odpowiedź na moje pytanie. – Jim

+0

Nie zapominaj, że możesz głosować na odpowiedź i ją akceptować :) –

+1

tylko dla kompletności: 'd6 (1)' podaje liczbę, ale np. 'd6 (2)' daje '{ok, [wartość1, wartość2]}, co może prowadzić do innych błędów. – ZeissS