This is the directory structure.
src/
animal.hrl
people.hrl
data_animal.erl
data_people.erl
test.erl
test_macro.erl
animal.hrl
%% The record definition of animal.
-ifndef(ANIMAL).
-define(ANIMAL,true).
-record(animal,{
id,
animal_name,
age
}).
-endif.
people.hrl
%% The record definition of people.
-ifndef(PEOPLE).
-define(PEOPLE,true).
-record(people,{
id,
people_name,
age
}).
-endif.
data_animal.erl
%% The data file of animal.
-module(data_animal).
-include("animal.hrl").
%% API
-export([get/1,get_ids/0]).
get(1)->
#animal{
id=1,
animal_name="cat",
age=23
};
get(2)->
#animal{
id=2,
animal_name="dog",
age=19
};
get(3)->
#animal{
id=3,
animal_name="tiger",
age=23
};
get(4)->
#animal{
id=4,
animal_name="pig",
age=19
};
get(_)->
undefined.
get_ids()->
[1,2,3,4].
data_people.erl
%% The data file of people.
-module(data_people).
-include("people.hrl").
%% API
-export([get/1,get_ids/0]).
get(1)->
#people{
id=1,
people_name="John",
age=23
};
get(2)->
#people{
id=2,
people_name="Ken",
age=19
};
get(3)->
#people{
id=3,
people_name="Tom",
age=23
};
get(4)->
#people{
id=4,
people_name="Healthy",
age=19
};
get(_)->
undefined.
get_ids()->
[1,2,3,4].
Notice that, for data_animal.erl and data_people.erl, the parameter of get/1is the record's id of the return value, and the return value of get_ids/0 is a list of get/1's parameters.
test.erl
-module(test).
%% API
-export([get_animal_list/1,get_people_list/1]).
-include("animal.hrl").
-include("people.hrl").
get_animal_list(Age)->
Fun=fun(Id,Acc)->
case data_animal:get(Id) of
#animal{age=Age}=Conf->
[Conf|Acc];
_->
Acc
end
end,
lists:foldl(Fun,[],data_animal:get_ids()).
get_people_list(Age)->
Fun=fun(Id,Acc)->
case data_people:get(Id) of
#people{age=Age}=Conf->
[Conf|Acc];
_->
Acc
end
end,
lists:foldl(Fun,[],data_people:get_ids()).
I want to get the data of animal and people, whose ages are 23, so I write 2 functions, get_animal_list/1, get_people_list/1.
I run
1> c(data_animal),c(data_people),c(test).
{ok,test}
2> test:get_people_list(23).
[{people,3,"Tom",23},{people,1,"John",23}]
3> test:get_animal_list(23).
[{animal,3,"tiger",23},{animal,1,"cat",23}]
Suddenly, I find that the 2 functions share the same pattern. Then I attempt to write a macro get_list, and make 2 calls instead.
test_macro.erl
-module(test_macro).
%% API
-export([get_animal_list/1,get_people_list/1]).
-include("animal.hrl").
-include("people.hrl").
-define(get_list(DataMod,Record,Age),(
Fun=fun(Id,Acc)->
case DataMod:get(Id) of
#Record{age=Age}=Conf->
[Conf|Acc];
_->
Acc
end
end,
lists:foldl(Fun,[],DataMod:get_ids())
)).
get_animal_list(Age)->
?get_list(data_animal,animal,Age).
get_people_list(Age)->
?get_list(data_people,people,Age).
But I got the compile error:
4> c(test_macro).
test_macro.erl:22: syntax error before: ','
test_macro.erl:25: syntax error before: ','
test_macro.erl:4: function get_animal_list/1 undefined
test_macro.erl:4: function get_people_list/1 undefined
error
Tell me why~y~y~
Thank you all! I have 3 questions now.
- Is my code really not Erlang-like? It's extracted from my company's project. Am I still thinking in OOP? Or so do the programming guys in my company?
- Thanks to @mlambrichs 's advice. It works, but I still wonder why my code get the compilation error? Is it because Erlang preprocessor is a one-pass scanner, so it fails to recognize
#Record{age=Age}? According to @mlambrichs 's suggestion, I try to change the macro
-define(get_list(DataMod, Record, Age), [P || P <- lists:map(fun(Id) -> DataMod:get(Id) end, DataMod:get_ids()), P#Record.age =:= Age] ).
into a function
get_list(DataMod, Record, Age)->
[P || P <- lists:map(fun(Id) -> DataMod:get(Id) end,
DataMod:get_ids()),
P#Record.age =:= Age].
Then I get the compilation error:
syntax error before: Record
animal.erland apeople.erland write interface functions to the data so that they behave as their own abstract data types. To carry that further in Erlangdom (and make it OOP in the way Alan Kay intended) makepeople.erlandanimal.erlmodules define processes, so that each instance is an animal or a person. Write interface functions to those processes as accessors. In this way things like game servers are simplified in Erlang. - zxq9