2011-02-10 30 views
6

Ví dụ tôi có kỷ lục erlang:Erlang danh sách kỷ lục mục

-record(state, {clients 
      }). 

Tôi có thể kiếm được từ danh sách khách hàng lĩnh vực?

Điều đó tôi có thể giữ trong ứng dụng được gửi như trong danh sách bình thường? Và làm thế nào tôi có thể thêm một số giá trị trong danh sách này?

Cảm ơn bạn.

Trả lời

7

Có lẽ bạn có nghĩa là một cái gì đó như:

-module(reclist). 
-export([empty_state/0, some_state/0, 
     add_client/1, del_client/1, 
     get_clients/1]). 

-record(state, 
    {  
      clients = [] ::[pos_integer()], 
      dbname   ::char() 
    }).  

empty_state() -> 
    #state{}. 

some_state() -> 
    #state{ 
      clients = [1,2,3], 
      dbname = "QA"}. 

del_client(Client) -> 
    S = some_state(), 
    C = S#state.clients, 
    S#state{clients = lists:delete(Client, C)}. 

add_client(Client) -> 
    S = some_state(), 
    C = S#state.clients, 
    S#state{clients = [Client|C]}. 

get_clients(#state{clients = C, dbname = _D}) -> 
    C. 

Test:

1> reclist:empty_state(). 
{state,[],undefined} 
2> reclist:some_state(). 
{state,[1,2,3],"QA"} 
3> reclist:add_client(4). 
{state,[4,1,2,3],"QA"} 
4> reclist:del_client(2). 
{state,[1,3],"QA"} 

::[pos_integer()] có nghĩa là loại lĩnh vực này là danh sách các giá trị nguyên dương, bắt đầu từ 1; đó là gợi ý cho công cụ phân tích dialyzer, khi nó thực hiện kiểm tra kiểu.

Erlang cũng cho phép bạn sử dụng phù hợp với mô hình trên hồ sơ:

5> reclist:get_clients(reclist:some_state()). 
[1,2,3] 

Đọc thêm:


@JUST MY OPINION chính xác của answer làm tôi nhớ rằng tôi thích cách Haskell đi về nhận giá trị của các trường trong kiểu dữ liệu.

Dưới đây là một định nghĩa của một kiểu dữ liệu, bị đánh cắp từ Learn You a Haskell for Great Good!, mà thúc đẩy cú pháp kỷ lục:

data Car = Car {company :: String 
       ,model :: String 
       ,year :: Int 
       } deriving (Show) 

Nó tạo ra các chức năng company, modelyear, mà lĩnh vực tra cứu trong các loại dữ liệu. Đầu tiên chúng ta tạo ra một chiếc xe mới:

ghci> Car "Toyota" "Supra" 2005 
Car {company = "Toyota", model = "Supra", year = 2005} 

Hoặc, sử dụng cú pháp kỷ lục (theo thứ tự của các lĩnh vực không quan trọng):

ghci> Car {model = "Supra", year = 2005, company = "Toyota"} 
Car {company = "Toyota", model = "Supra", year = 2005} 
ghci> let supra = Car {model = "Supra", year = 2005, company = "Toyota"} 
ghci> year supra 
2005 

Chúng tôi thậm chí có thể sử dụng mô hình phù hợp:

ghci> let (Car {company = c, model = m, year = y}) = supra 
ghci> "This " ++ C++ " " ++ m ++ " was made in " ++ show y 
"This Toyota Supra was made in 2005" 

Tôi nhớ đã có những nỗ lực để thực hiện một cái gì đó tương tự như cú pháp hồ sơ của Haskell trong Erlang, nhưng không chắc chắn nếu họ đã thành công.

Một số bài viết, liên quan đến những nỗ lực:

Dường như LFE sử dụng macro, tương tự với những gì cung cấp Scheme (Racket, ví dụ), khi bạn muốn tạo ra một giá trị mới của một số cấu trúc:

> (define-struct car (company model year)) 
> (define supra (make-car "Toyota" "Supra" 2005)) 
> (car-model supra) 
"Supra" 

Tôi hy vọng chúng tôi sẽ có một cái gì đó gần với cú pháp ghi Haskell trong tương lai, điều đó sẽ thực sự hữu ích và tiện dụng.

+0

ewps, đó là 'dialyzer'. Thông tin thêm về Erlang [Records] (http://www.erlang.org/doc/programming_examples/records.html). –

+0

Ồ, nó phải là 'clients = [] :: [pos_integer()], ' –

+0

Bạn không thể sửa bài của riêng bạn để cập nhật điều đó với 2600 điểm tín dụng của bạn? – ndim

1

Nếu bạn chỉ thêm hoặc xóa các mục đơn lẻ khỏi danh sách khách hàng ở trạng thái bạn có thể cắt giảm khi nhập bằng macro.

-record(state, {clients = [] }). 

-define(AddClientToState(Client,State), 
    State#state{clients = lists:append([Client], State#state.clients) }). 

-define(RemoveClientFromState(Client,State), 
    State#state{clients = lists:delete(Client, State#state.clients) }). 

Đây là một escript bài kiểm tra đó chứng tỏ:

#!/usr/bin/env escript 

-record(state, {clients = [] }). 

-define(AddClientToState(Client,State), 
    State#state{clients = lists:append([Client], State#state.clients)} ). 

-define(RemoveClientFromState(Client,State), 
    State#state{clients = lists:delete(Client, State#state.clients)} ). 


main(_) -> 

    %Start with a state with a empty list of clients. 
    State0 = #state{}, 
    io:format("Empty State: ~p~n",[State0]), 

    %Add foo to the list 
    State1 = ?AddClientToState(foo,State0), 
    io:format("State after adding foo: ~p~n",[State1]), 

    %Add bar to the list. 
    State2 = ?AddClientToState(bar,State1), 
    io:format("State after adding bar: ~p~n",[State2]), 

    %Add baz to the list. 
    State3 = ?AddClientToState(baz,State2), 
    io:format("State after adding baz: ~p~n",[State3]), 

    %Remove bar from the list. 
    State4 = ?RemoveClientFromState(bar,State3), 
    io:format("State after removing bar: ~p~n",[State4]). 

Kết quả:

Empty State: {state,[]} 
State after adding foo: {state,[foo]} 
State after adding bar: {state,[bar,foo]} 
State after adding baz: {state,[baz,bar,foo]} 
State after removing bar: {state,[baz,foo]} 
+1

Trong các trường hợp này, tôi thích sử dụng hàm thay vì macro. Làm cho mã dễ theo dõi hơn, tái cấu trúc và kiểm tra. –

3

Yasir's answer là điều đúng, nhưng tôi sẽ cho bạn thấy tại sao nó hoạt động đường nó hoạt động để bạn có thể hiểu các bản ghi tốt hơn một chút.

Bản ghi trong Erlang là một bản hack (và một bản khá xấu). Sử dụng định nghĩa bản ghi từ câu trả lời của Yasir ...

-record(state, 
    {  
      clients = [] ::[pos_integer()], 
      dbname   ::char() 
    }). 

... khi bạn khởi tạo này với #state{} (như Yasir đã làm trong empty_state/0 chức năng), những gì bạn thực sự có được lại là thế này:

{state, [], undefined} 

Đó là để nói rằng "bản ghi" của bạn chỉ là một tuple được gắn thẻ với tên của bản ghi (state trong trường hợp này), sau đó là nội dung của bản ghi. Bên trong BEAM chính nó không có hồ sơ. Nó chỉ là một tuple với các loại dữ liệu Erlang chứa bên trong nó. Đây là chìa khóa để hiểu cách mọi thứ hoạt động (và những hạn chế của bản ghi để khởi động).

Bây giờ khi Yasir đã làm điều này ...

add_client(Client) -> 
    S = some_state(), 
    C = S#state.clients, 
    S#state{clients = [Client|C]}. 

... bit S#state.clients dịch thành mã nội bộ trông giống như element(2,S). Bạn đang sử dụng, nói cách khác, các chức năng thao tác tiêu chuẩn tuple. S#state.clients chỉ là một cách tượng trưng để nói cùng một điều, nhưng theo cách cho phép bạn biết phần tử 2 thực sự là gì . Đó là cú pháp saccharine đó là một sự cải tiến trong việc theo dõi các lĩnh vực riêng lẻ trong các bộ dữ liệu của bạn theo cách dễ bị lỗi.

Bây giờ cho rằng S#state{clients = [Client|C]} bit cuối cùng, tôi không hoàn toàn tích cực như mã được tạo ra đằng sau hậu trường, nhưng nó có thể chỉ là công cụ đơn giản tương đương với {state, [Client|C], element(3,S)}. Nó:

  • thẻ một tuple mới với tên của hồ sơ (được cung cấp như #state),
  • bản các yếu tố từ S (quyết định bởi phần S#),
  • trừ các mảnh clients ghi đè bởi {clients = [Client|C]}.

Tất cả phép thuật này được thực hiện thông qua quá trình xử lý trước hậu trường.

Hiểu cách bản ghi hoạt động hậu trường có lợi cho cả việc hiểu mã được viết bằng cách sử dụng hồ sơ cũng như để hiểu cách sử dụng bản thân (không kể đến lý do tại sao mọi thứ có vẻ "hợp lý" không hoạt động với hồ sơ - bởi vì chúng không thực sự tồn tại trong máy trừu tượng ...).

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