编译错误:在Erlang中记录宏的替换

时间:2017-08-30 02:20:47

标签: compilation macros erlang record

这是目录结构。

  

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

请注意,对于data_animal.erldata_people.erlget/1的参数是返回值的记录ID,而get_ids/0的返回值是列表get/1的参数。

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

我想获得动物和人的数据,年龄为23岁,所以我写了2个函数,get_animal_list/1, get_people_list/1

我跑

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}]

突然间,我发现2个功能共享相同的模式。然后我尝试编写宏get_list,然后进行2次调用。

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

但是我收到了编译错误:

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

告诉我为什么〜y~y~

谢谢大家! 我现在有3个问题。

  1. 我的代码真的不像Erlang吗?它是从我公司的项目中提取的。我还在想OOP吗?或者我公司的编程人员呢?
  2. 感谢@mlambrichs的建议。它工作,但我仍然想知道为什么我的代码得到编译错误?是因为Erlang预处理器是单程扫描程序,所以它无法识别#Record{age=Age}
  3. 根据@mlambrichs的建议,我尝试更改宏

    -define(get_list(DataMod,Record,Age),   [P || P< - lists:map(fun(Id) - > DataMod:get(Id)end,     DataMod:get_ids()),     P#Record.age =:=年龄] )。

  4. 进入一个函数

    get_list(DataMod, Record, Age)->
      [P || P <- lists:map(fun(Id) -> DataMod:get(Id) end,
        DataMod:get_ids()),
        P#Record.age =:= Age].
    

    然后我收到编译错误: syntax error before: Record

1 个答案:

答案 0 :(得分:1)

错误的原因是错位的(&#39;应删除:

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

EDIT   您添加了一些我想开始回答的问题。

  • 我的代码真的不像Erlang吗?
    • 宏的用法。在您的情况下,没有必要使用宏。
    • 一般来说:你想隐瞒人和动物使用什么样的记录这一事实。这个实现应该被你的界面屏蔽。您可以定义一个getter函数来处理正确模块中的函数。 PLS。阅读我的重写建议。
  • 它有效,但我仍然想知道为什么我的代码会出现编译错误?请参阅答案的顶部。
  • ....我尝试更改宏.... 你是对的,该功能无法编译。显然需要重写。

像这样:

get_list(DataMod, Age) ->
    [ P || P = {_,_,_,A} <- lists:map(fun(Id) -> DataMod:get(Id) end,
           DataMod:get_ids()),
           A =:= Age].
  

修改

接受重写。你想要的是功能测试中两个列表的串联(你的测试/ 0,我的测试/ 1)。使用逗号不会为您执行此操作。 ; - )

test(X)->
  ?get_list(data_animal,X) ++
  ?get_list(data_people,X).

让我们修复get_list宏。你的宏定义get_list有3个参数,只需要2.当你在get_people_list / 1和get_animal_list / 1中使用Record时,为什么要使用Record作为参数?例如,试试这个:

-define(get_list(DataMod, Y),
   case DataMod of
      data_animal -> get_animal_list(Y);
      data_people -> get_people_list(Y);
      _Else -> []
   end
)

总的来说,测试模块中有很多代码复制。作为@ yjcdll的建议的后续,将界面功能移动到动物和人们的自己的模块。

让我们看一下您的数据模块及其获取功能。

我建议将所有人的记录放在一个数组中,在你的情况下是在data_people模块中。

people() -> [
   #people{ id=1, people_name="John", age=23 },
   #people{ id=2, people_name="Ken", age=19 },
   #people{ id=3, people_name="Tom", age=23 },
   #people{ id=4, people_name="Healthy", age=19 } ].

接下来,您需要一个getter函数才能获得具有特定年龄的人:

get(Age) ->
   [X || X <- people(), is_age( X, Age )].

is_age / 2函数将是:

is_age( Person, Age ) ->
   Person#people.age =:= Age.

因此,在模块测试中,你的get_people_list / 1会变得更加简单。

get_people_list(Age) ->
   data_people:get(Age).

等等。一直在寻找与您已经在某处使用过的代码看起来非常相似的代码。试着表现得像一个理智,懒惰的程序员。懒惰=好。 ; - )

编辑:OP必须坚持给出的模块。因此重写宏是:

-define(get_list(DataMod, Record, Age),
   [P || P <- lists:map(fun(Id) -> DataMod:get(Id) end, 
                                   DataMod:get_ids()), 
         P#Record.age =:= Age]
).