Erlang: есть ли эквивалент директивы препроцессора C ##? - PullRequest
3 голосов
/ 14 сентября 2009

Есть ли эквивалент в директиве препроцессора C ## в Erlang?

Допустим, я хочу объединить два атома () с помощью директивы препроцессора -define, как бы я сделал это без , имеющего побочные эффекты во время выполнения?

Ответы [ 6 ]

4 голосов
/ 15 сентября 2009

Вы можете получить достаточно близкий результат, используя преобразования синтаксического анализа. Следующий parse_transform ищет «atom1 ++ atom2» и преобразует его в «atom1atom2» во время компиляции.

пример модуля

-module(z).

-export([z/0]).

-compile({parse_transform, zt}).

z() -> concat ++ enate.

компиляция с 'S' доказывает, что он действительно сцеплен во время компиляции:

{function, z, 0, 2}.
  {label,1}.
    {func_info,{atom,z},{atom,z},0}.
  {label,2}.
    {move,{atom,concatenate},{x,0}}.
    return. 

работает как положено:

1> z:z().
concatenate

модуль, содержащий преобразование синтаксического анализа:

-module(zt).

-export([parse_transform/2]).

parse_transform(AST, _Options) ->
  [parse(T) || T <- AST].

parse({function, _, _, _, _} = T) ->
  erl_syntax_lib:map(fun hashhash/1, T);
parse(T) -> T.

hashhash(Tree) ->
  erl_syntax:revert(
    case erl_syntax:type(Tree) of
      infix_expr ->
        Op = erl_syntax:infix_expr_operator(Tree),
        Left = erl_syntax:infix_expr_left(Tree),
        Right = erl_syntax:infix_expr_right(Tree),
        case {erl_syntax:operator_name(Op), erl_syntax:type(Left), erl_syntax:type(Right)} of
          {'++', atom, atom} ->
            erl_syntax:atom(erl_syntax:atom_literal(Left) ++ erl_syntax:atom_literal(Right));
          _ ->
            Tree
        end;
      _ ->
        Tree
    end
  ).

РЕДАКТИРОВАТЬ: отредактировано для "перегрузки" оператора infix ++. Предыдущая версия использовала функцию '##'.

1 голос
/ 15 сентября 2009

На самом деле вы не можете делать что-либо в макросе, это просто текстовая замена на уровне токенов. Нотабене вы работаете с исходным кодом и не оцениваете его. Если вам нужны более сложные типы подстановки, вам нужно использовать преобразование синтаксического анализа.

Если вы пишете макрос конкатенации, вы всегда можете использовать форму ?? Arg, чтобы получить аргумент в виде строки. Смотрите раздел препроцессора в электронном справочном руководстве.

Конечно, действительно интересный вопрос: почему вы хотите объединить два атома во время компиляции? Я предполагаю, что это вывод другого макроса, иначе не было бы смысла делать это.

1 голос
/ 15 сентября 2009

Я не уверен, что понимаю, что вы спрашиваете, но я сделаю удар.

-define(CATATOM(A, B), list_to_atom(list:concat(atom_to_list(A), atom_to_list(B)))).
AtomA = atom1.
AtomB = atom2.
NewAtom = ?CATATOM(AtomA, AtomB). % NewAtom is atom1atom2

или, может быть, вы имели в виду это?

-define(CATATOM(A, B), AB).
NewAtom = ?CATATOM(atom1, atom2). % NewAtom is atom1atom2

хотя я не уверен, какой смысл использовать новую секунду. Так как было бы проще написать atom1atom2 вместо макроса.

Второй не будет иметь побочных эффектов во время выполнения. Первый вызовет побочные эффекты во время выполнения, так как результатом макроса является 3 функции для запуска во время выполнения.

0 голосов
/ 15 сентября 2009

В одном из ваших ответов вы упоминаете, что хотите параметризировать модули - это можно сделать во время выполнения ...

Академическая статья на нем здесь .

Mochiweb использует его.

0 голосов
/ 15 сентября 2009

Существует концепция анализа преобразования, которая позволяет объединять атомы во время компиляции.

0 голосов
/ 14 сентября 2009

я думаю, что нет. И я думаю, что из-за этого вы можете делать все это во время выполнения без побочных эффектов

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...