2011-02-10 3 views
6

을 내가 얼랑 기록이 있습니다얼랑 기록 항목 목록 예를 들어

-record(state, {clients 
      }). 

내가 클라이언트 필드 목록에서 만들 수 있습니까?

정상적인 목록으로 제출 한 클라이언트에 보관할 수 있습니까? 그리고이 목록에 몇 가지 값을 어떻게 추가 할 수 있습니까?

감사합니다.

답변

7

어쩌면 당신은 같은 의미 :

-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. 

테스트 :

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()] 필드의 타입이 1부터 양의 정수 값의 목록이 있음을 의미합니다; 유형 검사를 수행 할 때 분석 도구 dialyzer에 대한 힌트입니다.

얼랑 또한 기록에 패턴 매칭 사용 할 수 있습니다 :

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

추가 읽기 :


@JUST MY 올바른 OPINION의 answer은 하스켈이 데이터 유형의 필드 값을 얻는 방법을 좋아한다는 것을 기억하게했습니다. 그것은 기능 company, modelyear, 데이터 타입에 해당 조회 필드를 생성

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

:

여기 레코드 구문을 활용 Learn You a Haskell for Great Good! 도난 데이터 형식의 정의이다.

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" 
: 우리는 심지어 패턴 매칭을 사용할 수 있습니다

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 

: 기록 구문 (중요하지 않습니다 필드의 순서)를 사용하여,

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

또는 : 우리는 먼저 새 차를 만들

Erlang에서 Haskell의 레코드 구문과 비슷한 것을 구현하려고 시도했지만 기억이 잘 안 나는지를 기억합니다. 이러한 시도와 관련된

일부 게시물 :

LFE는 당신이 어떤 구조의 새 값을 생성 할 때 (예를 들어, Racket) 방식을 제공하는 기능과 유사 매크로를 사용하는 것 같다

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

나는 우리가 '희망을 미래에 Haskell 레코드 구문에 가까운 것이 있다면, 실제로 유용하고 편리 할 것입니다.

+0

ewps, '투석기'입니다. Erlang [Records]에 대한 자세한 정보 (http://www.erlang.org/doc/programming_examples/records.html). –

+0

아, 그것은'clients = [] :: [pos_integer()], –

+0

이어야합니다. 2600 크레딧 포인트로 업데이트하기 위해 자신의 포스트를 편집 할 수 없습니까? – ndim

1

상태의 클라이언트 목록에서 단일 항목 만 추가하거나 제거하는 경우 매크로를 사용하여 타이핑하는 것을 줄일 수 있습니다. 여기

-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) }). 

을 보여줍니다 테스트 escript입니다 :

#!/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]). 

결과 :

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

이런 종류의 경우 매크로 대신 함수를 사용하는 것을 선호합니다. 코드를 따르기 쉽고, 리팩터링하고 테스트합니다. –

3

Yasir's answer 올바른 일이지만, 나는 그것이 방식으로 작동하는 이유를 보여 드리겠습니다 그것은 당신이 조금 더 나은 기록을 이해할 수 있도록 작동합니다.

얼랑 (Erlang)의 기록은 해킹 (그리고 꽤 추한 것)입니다.

{state, [], undefined} 

: 당신이 (시르가 empty_state/0 기능에서와 마찬가지로) #state{}으로이 인스턴스를 야시의 대답에서 레코드 정의 ...

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

를 ... 사용하여, 당신이 정말 돌아 가야하는 것은 이것이다 즉, "레코드"는 레코드 이름 (이 경우 state)과 함께 레코드 집합의 태그가 붙은 튜플입니다. 빔 내부에 레코드가 없습니다. Erlang 데이터 유형을 포함하는 또 다른 튜플 일뿐입니다. 이것은 어떻게 작동하는지 (그리고 부팅 할 레코드의 한계)를 이해하는 열쇠입니다. 야세르 이런 짓을 지금

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

... S#state.clients 비트 element(2,S)과 같은 내부 코드로 변환합니다. 즉, 표준 튜플 조작 함수를 사용하고 있습니다. S#state.clients은 같은 것을 말하는 상징적 인 방법 일 뿐이지 만 실제로 어떤 요소 2가 인지 알 수있는 방식으로입니다. 이것은 문법상의 사카린으로, 튜플의 개별 필드를 오류가 발생하기 쉬운 방식으로 추적하는 것보다 개선 된 기능입니다.

이제 마지막 코드 인 S#state{clients = [Client|C]} 비트에 대해 배후에서 어떤 코드가 생성되는지는 확실하지 않지만, {state, [Client|C], element(3,S)}과 같은 간단한 코드 일 가능성이 높습니다. 그것은 :

  • 는 (#state 제공) 레코드의 이름으로 새로운 튜플
  • 복사합니다 (S# 부에 의해 결정) S의 요소에 의해 재정의 clients 편 제외
  • 태그 {clients = [Client|C]}.

이 마법은 모두 무대 뒤에서 전처리 해킹을 통해 이루어집니다.

레코드가 장면 뒤에서 어떻게 작동하는지 이해하면 레코드를 사용하여 작성된 코드를 이해하고이를 사용하는 방법을 이해하는 데 모두 도움이됩니다. ("이해가가는 것"이 ​​레코드와 함께 작동하지 않는 이유를 이해하는 것은 물론 말할 필요도 없음) 왜냐하면 그것들은 추상 기계에 실제로 존재하지 않기 때문입니다.