2010-09-29 42 views
5

Tôi đã tìm ra Erlang kiểu bẹ: đuôi-đệ quy với các chức năng mà phải mất tất cả các "biến không thay đổi":Đếm trong Erlang (? Làm thế nào để tăng một biến)

%% does something, 80 bytes at a time 
loop(Line, File) -> loop(Line, File, 0). 
loop(Line, File, Count) -> 
    do_something(Line, Count), 
    case file:read(File, 80) of 
     {ok, Line2} -> loop(Line2, File, Count + 1); 
     eof -> file:close(File); 
     {error, Reason} -> {error, Reason} 
    end. 

Nhưng cách tốt nhất để tăng số lượt truy cập trong Erlang là gì? Trong hầu hết các ngôn ngữ lập trình, cách bạn đếm mọi thứ bằng cách tăng một biến (ví dụ: count += 1;). Biến của Erlang không thay đổi, vì vậy chúng ta phải sáng tạo. May mắn thay, chúng tôi có các tùy chọn ...

Chúng tôi có thể chuyển biến Số lượt truy cập với các chức năng của chúng tôi và tăng biến đó với mỗi lệnh gọi hàm. Chúng tôi có thể sử dụng từ điển quy trình để lưu trữ số lượng và getput để tăng số lượng từ điển đó. Chúng tôi có thể sử dụng ETS, lưu trữ dữ liệu cục bộ cho các quy trình. Chúng tôi có thể sử dụng quy trình truy cập (!!!):

loop(Count) ->        
    receive         
     { incr } -> 
      loop(Count + 1);    
     { report, To } ->      
      To ! { count, Count },    
      loop(Count)       
    end.          

incr(Counter) -> 
    Counter ! { incr }. 

get_count(Counter) ->  
    Counter ! { report, self() }, 
    receive 
     { count, Count } -> Count 
    end. 

Tôi chắc chắn cũng có những cách khác, tùy thuộc vào phạm vi. Những gì được coi là "thực hành tốt nhất" để tăng một biến trong Erlang?

+0

Câu hỏi này không quá có ý nghĩa nếu không có trường hợp sử dụng. Bạn có thể làm 'danh sách: foldl' để đếm những thứ trong một danh sách (hoặc' filter' + 'length'). Nếu bạn đang đếm các cuộc gọi 'gen_server', bạn làm điều đó với trạng thái máy chủ của bạn một cách dễ dàng. – Dustin

+0

Tôi đã thiếu PHP ... tĩnh $ i; $ i ++; – Rolf

Trả lời

3

Tất cả phụ thuộc vào những gì bạn đang sử dụng bộ đếm. Mọi thứ toàn cục như số lượng thư được xử lý bởi hệ thống q nên sử dụng ets: update_counter. Nếu nó không phải là toàn cầu, tôi thường chỉ bao gồm nó trong các tham số như bạn đã cho thấy.

9

Không sử dụng từ điển quy trình.

Các vòng lặp 'bình thường' mà bạn đang mong đợi (tức là một vòng lặp for hoặc một do while) thường được thực hiện trong một hàm đệ quy trong Erlang vì vậy nếu bạn đang tăng một bộ đếm 'bình thường' làm điều đó trong hàm gọi như bạn hiển thị lên hàng đầu.

Không sử dụng từ điển quy trình.

Trong trường hợp bạn bỏ lỡ, tôi có thể chỉ ra rằng bạn không nên sử dụng từ điển quy trình.

+3

Ngoài ra, không sử dụng từ điển quy trình. –

+2

Tuy nhiên, từ điển quy trình được sử dụng trong hầu hết mọi ứng dụng trong phân phối Erlang/OTP. Giống như 'inets'. Hoặc 'orber'. Hoặc 'docbuilder'. Hoặc 'ic'. Hoặc 'megaco'. Hoặc 'tv'. Hoặc 'cosNotification'. Hoặc 'eunit'. Hoặc 'reltool'. Hoặc 'trình biên dịch'. Hoặc 'erts'. Hoặc 'test_server'. Hoặc 'appmon'. Hoặc 'ssh'. Hoặc 'trình gỡ rối'. Hoặc 'kernel'. Hoặc 'gs'. Hoặc 'os_mon'. Hoặc 'pman'. Hoặc 'stdlib'. Hoặc 'percept'. Hoặc 'xmerl'. Hoặc 'asn1'. Hoặc 'mnesia'. Hoặc 'common_test'. Hoặc 'parsetools'. Hoặc 'dialyzer'. Hoặc ... Nó sẽ dễ dàng hơn để tin rằng "không có từ điển quá trình" meme nếu cộng đồng ở lại trên tin nhắn. –

+3

Quy tắc chung là "nếu bạn tự hỏi liệu bạn có nên sử dụng từ điển quy trình hay không, bạn không nên sử dụng từ điển" và "bạn sẽ biết khi nào bạn cần". Để công bằng, trong khi có sử dụng từ điển quá trình hợp lệ, hầu hết trong số họ không phải làm gì với 'các biến gia tăng' mà là 'lưu trữ siêu dữ liệu quy trình', theo như tôi biết. –

0

Cách tiêu chuẩn tăng bộ đếm giống như trong ví dụ đầu tiên của bạn. Bằng cách thêm một biến vào cuộc gọi và tăng nó. Tôi nghĩ rằng bạn bị lẫn lộn bởi việc thiếu các vòng lặp và khả năng cập nhật các giá trị.

Lưu ý rằng:

repeat(Times) when Times >= 0 -> repeat(0, Times). 

repeat(Times, Times) -> done; 
repeat(N, Times) -> 
    do_a_side_effect, 
    repeat(N + 1, Times). 

biên dịch để (nhiều hơn hoặc ít hơn) điều tương tự như (trong mã giả):

repeat(Times) -> 
    while (N < Times) { 
    do_a_side_effect 
    N++ 
    } 
    return done 

Nếu bạn muốn tích lũy kết quả có nhiều cách để làm Cũng vậy.

Hoặc sử dụng gói danh sách hoặc tích lũy kết quả bản thân:

loop(File) -> 
    {ok, Fd} = file:open(File), 
    loop(Fd, 0, []). 

loop(Fd, Count, Acc) -> 
    case file:read(Fd, 80) of 
    {ok, Line} -> 
     Result = do_something(Line, Count), 
     loop(Fd, Count + 1, [Result | Acc]); 
    eof -> 
     file:close(File), 
     {Count, lists:reverse(Acc)}; 
    {error, Reason} -> {error, Reason} 
    end. 

Hoặc một cái gì đó tương tự dựa trên ví dụ của bạn.

Chỉnh sửa: được trả về Đếm như một phần của giá trị trả về, vì nó có vẻ quan trọng.

2

Tôi nghĩ rằng bạn đã tạo ra một lượng lớn trong số đó, trong khi bạn có thể xử lý nó dễ dàng hơn nhiều.
xem xét thực hiện này của vòng lặp for trong Erlang:

for(Max, Max, F) -> [ F(Max) ]; 
for(I, Max, F) -> [ F(I) | for(I+1, Max, F) ]. 

Trong khi F là chức năng mà bạn muốn lưu kết quả của nó cho các giá trị I để Max.
Đó không phải là điều dễ hiểu hơn?

Các vấn đề liên quan