You can get a fairly close result using parsing conversions. The following parse_transform searches for "atom1 ++ atom2" and converts it to "atom1atom2" at compile time.
Module example
-module(z).
-export([z/0]).
-compile({parse_transform, zt}).
z() -> concat ++ enate.
compilation with 'S' proves that it really was merged at compile time:
{function, z, 0, 2}.
{label,1}.
{func_info,{atom,z},{atom,z},0}.
{label,2}.
{move,{atom,concatenate},{x,0}}.
return.
works as expected:
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
).
EDIT: "" infix ++. "##".