2009-07-14 26 views
9

Tôi đang viết một hàm Erlang in mọi số chẵn lên đến một tham số đã cho.Trong Erlang, có cách nào để tạo ra một hàm rỗng không?

Cho đến nay, tôi đã viết chức năng với lính gác như thế này:

printEven(I,N) when I < N -> 
    if 
    I rem 2 == 0 -> io:format("~p~n",[I]), printEven(I+1,N); 
    I rem 2 == 1 -> printEven(I+1,N) 
    end; 
printEven(I,N) -> 
    io:format("Done"). 

Tôi thực sự muốn có trường hợp cuối cùng chỉ thoát tự động và không cần phải in bất cứ điều gì trong hàm. Tôi đã thử chỉ cần loại bỏ nó, nhưng sau đó một lỗi xảy ra kể từ khi đệ quy được thực hiện, một lỗi được ném.

Tôi làm cách nào để thực hiện việc này? Có cái gì đó giống như một từ khóa 'pass' hoặc 'yield' trong erlang?

+0

Umm, mã này không thể biên dịch - mệnh đề đầu tiên sẽ phải kết thúc bằng dấu chấm phẩy không phải là dấu chấm hết. Bạn có đang chạy nó trong trình bao không? Nếu bạn là sau đó nó sẽ luôn luôn in những gì nó trả về và nó luôn luôn trả về một cái gì đó. Nếu bạn không chạy nó trong vỏ sau đó chỉ cần thả các định dạng io: –

Trả lời

11

OK, lần đầu tiên xác định các chức năng:

printEven(I,N) when I >= N -> ok; 
printEven(I,N)    -> 
    if 
    I rem 2 == 0 -> io:format("~p~n",[I]), printEven(I+1,N); 
    I rem 2 == 1 -> printEven(I+1,N) 
    end. 

Erlang là một ngôn ngữ lập trình chức năng và (theo định nghĩa) chức năng 'có' một giá trị, do đó bạn sẽ nhận được 'cái gì' trở lại. Theo quy ước, điều bạn nhận được khi hoàn thành một hàm mà bạn đang sử dụng cho các tác dụng phụ là nguyên tử 'ok', đó là cách tốt nhất để sử dụng ở đây.

Bạn có thể 'âm thầm hủy' giá trị trả lại nếu muốn. Bạn làm điều đó khi bạn gọi hàm bằng mô hình kết hợp với 'không quan tâm' biến (được gạch dưới):

_ = printEven(3,9), 

hoặc bằng cách gọi hàm mà không có một mô hình phù hợp:

printEven(3,9), 

Tuy nhiên, bạn là tốt hơn để luôn luôn kiểm tra giá trị trả về bởi mô hình kết hợp khi bạn gọi một hàm:

ok = printEven(3,9), 

Đây là aa thói quen thực sự tốt để có được vào bởi vì bạn sẽ được sử dụng rất nhiều lib chức năng rary trả lại mã lỗi như bạn có thể nhìn thấy từ thông số kỹ thuật của họ:

@spec funky(X) -> [ok | {error, bad_op} | {error, wig_out}] 

tác dụng phụ Nếu sôi nổi có bạn muốn biết nó đã thất bại tại bằng cách gọi nó với một mô hình phù hợp vì vậy nó sẽ sụp đổ ở đây và bây giờ nếu không sôi nổi:

ok = funky(99), 

Nếu bạn kết hợp nó với '_' hoặc bỏ qua các giá trị trả về nó sẽ sụp đổ 268 dòng sau khi mojo của bạn hy vọng sôi nổi đã làm thang của mình, và sau đó nó là nhiều khó tìm hơn.

Đây là chương trình đường dẫn hạnh phúc được thực hiện trong Erlang. "Hãy để nó sụp đổ" là phương châm. Nếu bạn là người mới đến Erlang bạn sẽ thấy điều này rất bối rối - như đi bộ về trần truồng. Đừng lo lắng nắm lấy nó, nó là một điều tốt. Nó dẫn đến rất nhiều mã 'không được viết'.

(Bạn cũng nên có thói quen đưa mệnh đề mà kết thúc đệ quy như các khoản đầu như thể hiện ở đây - nó làm cho việc đọc mã sooo dễ dàng hơn nhiều khi bạn có một chức năng đa khoản.)

+0

Thực tế mã này không đủ, mệnh đề thứ hai nên được viết là: printEven (I, N) -> _ = nếu Tôi rem 2 == 0 -> io: format ("~ p ~ n", [TÔI]); Tôi rem 2 == 1 -> ok% in không có gì kết thúc, printEven (I + 1, N); Hãy nhớ rằng mệnh đề if trả về giá trị - có thể bạn sẽ không khớp với giá trị này trong trường hợp này nhưng tôi bị kẹt trong khớp để nhắc bạn rằng nó không :) –

+0

Không chỉ bạn có thể làm mọi thứ đẹp hơn bằng cách tránh phải viết hàm đệ quy gọi hai lần, bạn có thể làm cho mọi thứ đẹp hơn bằng cách tránh phải viết 'I rem 2' hai lần với câu lệnh case. Xem câu trả lời của tôi. – 7stud

1

Tôi tin rằng từ khóa là "ok"

4

chỉ trả về một nguyên tử.

inEven (I, N) -> done.

nên làm điều đó.

+0

Tôi không muốn một nguyên tử để in mặc dù, chỉ là những con số trong văn bản. – samoz

+0

nguyên tử sẽ không in. nó sẽ chỉ dừng vòng lặp. –

+0

Tôi nên làm rõ, bạn sẽ nhận thấy rằng giá trị trả về của printEven không bao giờ được sử dụng, vì vậy bạn có thể trả lại bất kỳ thứ gì không bao gồm một cuộc gọi đệ quy. –

2

Bạn cũng có thể kết hợp thử nghiệm ngay cả trong mệnh đề bảo vệ. Tôi cũng thích lừa nguyên tử được thực hiện - nó cho thấy trong mã của bạn rằng đó là mệnh đề hàm sẽ ngừng "đệ quy".

printEven(I, N) when I<N, I rem 2 == 0 -> 
    io:format("~p is even~n", [I]), 
    printEven(I+1, N); 
printEven(I,N) when I<N -> 
    printEven(I+1, N); 
printEven(I,N) -> 
    done. 
+0

Có cách nào để thoát âm thầm không? Không có nguyên tử? – samoz

+2

Không - tất cả các hàm trả về một giá trị. Bạn không thử nghiệm giá trị của hàm vì vậy tôi không chắc chắn tại sao lại quan trọng đối với bạn? –

0
printEven(Start, Stop) when Start =< Stop -> 
    case Start rem 2 of 
     0 -> io:format("~p~n", [Start]); %returns ok 
     _ -> do_nothing 
    end, 
    printEven(Start+1, Stop); 
printEven(Start, Stop) when Start > Stop -> 
    ok. 

giá trị của báo cáo trường hợp là một trong hai ok hoặc do_nothing, nhưng báo cáo trường hợp không phải là biểu hiện cuối cùng, vì vậy giá trị của nó sẽ không có giá trị trả về cho mệnh đề thứ nhất của hàm, và vì giá trị của biểu thức trường hợp không bị ràng buộc với một biến, giá trị đơn giản là bị loại bỏ.

Biểu thức cuối cùng trong mệnh đề chức năng đầu tiên thực sự là printEven(Start+1, Stop), và đó gọi hàm sẽ kết thúc trở ok khi đệ quy đến khi kết thúc của chuỗi và thực hiện printEven(Start, Stop) when Start > Stop -> ok;

printEven(1, 3) => ? 
        | 
        V 
      printEven(2, 3) => ? 
           | --side effect: output 2 
           V 
         printEven(3, 3) => ? 
              | 
              V 
             printEven(4, 3) => ok 

Điền vào giá trị để đổi lấy mỗi lần gọi hàm lên chuỗi cung cấp cho:

printEven(1, 3) => ok 
        ^
        | 
       printEven(2, 3) => ok 
           ^
           | 
         printEven(3, 3) => ok 
              ^
              | 
             printEven(4, 3) => ok 
-1

này sẽ làm điều đó:

printEven(I,N) -> ok. 
Các vấn đề liên quan