1%% Licensed under the Apache License, Version 2.0 (the "License"); 2%% you may not use this file except in compliance with the License. 3%% You may obtain a copy of the License at 4%% 5%% http://www.apache.org/licenses/LICENSE-2.0 6%% 7%% Unless required by applicable law or agreed to in writing, software 8%% distributed under the License is distributed on an "AS IS" BASIS, 9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10%% See the License for the specific language governing permissions and 11%% limitations under the License. 12%% 13%% @copyright 2000-2006 Richard Carlsson 14%% @author Richard Carlsson <carlsson.richard@gmail.com> 15%% 16%% @doc Core Erlang pattern matching compiler. 17%% 18%% <p>For reference, see Simon L. Peyton Jones "The Implementation of 19%% Functional Programming Languages", chapter 5 (by Phil Wadler).</p> 20%% 21%% @type cerl() = cerl:cerl(). 22%% Abstract Core Erlang syntax trees. 23%% @type cerl_records() = cerl:cerl_records(). 24%% An explicit record representation of Core Erlang syntax trees. 25 26-module(cerl_pmatch). 27 28%%-define(NO_UNUSED, true). 29 30-export([clauses/2]). 31-ifndef(NO_UNUSED). 32-export([transform/2, core_transform/2, expr/2]). 33-endif. 34 35-import(lists, [all/2, splitwith/2, foldr/3, keysort/2, foldl/3, 36 mapfoldl/3]). 37 38-define(binary_id, {binary}). 39-define(cons_id, {cons}). 40-define(tuple_id, {tuple}). 41-define(literal_id(V), V). 42 43 44%% @spec core_transform(Module::cerl_records(), Options::[term()]) -> 45%% cerl_records() 46%% 47%% @doc Transforms a module represented by records. See 48%% <code>transform/2</code> for details. 49%% 50%% <p>Use the compiler option <code>{core_transform, cerl_pmatch}</code> 51%% to insert this function as a compilation pass.</p> 52%% 53%% @see transform/2 54 55-ifndef(NO_UNUSED). 56-spec core_transform(cerl:c_module(), [_]) -> cerl:c_module(). 57 58core_transform(M, Opts) -> 59 cerl:to_records(transform(cerl:from_records(M), Opts)). 60-endif. % NO_UNUSED 61%% @clear 62 63 64%% @spec transform(Module::cerl(), Options::[term()]) -> cerl() 65%% 66%% @doc Rewrites all <code>case</code>-clauses in <code>Module</code>. 67%% <code>receive</code>-clauses are not affected. Currently, no options 68%% are available. 69%% 70%% @see clauses/2 71%% @see expr/2 72%% @see core_transform/2 73 74-ifndef(NO_UNUSED). 75-spec transform(cerl:cerl(), [_]) -> cerl:cerl(). 76 77transform(M, _Opts) -> 78 expr(M, env__empty()). 79-endif. % NO_UNUSED 80%% @clear 81 82 83%% @spec clauses(Clauses::[Clause], Env) -> {Expr, Vars} 84%% Clause = cerl() 85%% Expr = cerl() 86%% Vars = [cerl()] 87%% Env = rec_env:environment() 88%% 89%% @doc Rewrites a sequence of clauses to an equivalent expression, 90%% removing as much repeated testing as possible. Returns a pair 91%% <code>{Expr, Vars}</code>, where <code>Expr</code> is the resulting 92%% expression, and <code>Vars</code> is a list of new variables (i.e., 93%% not already in the given environment) to be bound to the arguments to 94%% the switch. The following is a typical example (assuming 95%% <code>E</code> is a Core Erlang case expression): 96%% <pre> 97%% handle_case(E, Env) -> 98%% Cs = case_clauses(E), 99%% {E1, Vs} = cerl_pmatch(Cs, Env), 100%% c_let(Vs, case_arg(E), E1). 101%% </pre> 102%% 103%% <p>The environment is used for generating new variables which do not 104%% shadow existing bindings.</p> 105%% 106%% @see rec_env 107%% @see expr/2 108%% @see transform/2 109 110-spec clauses([cerl:cerl(),...], rec_env:environment()) -> 111 {cerl:cerl(), [cerl:cerl()]}. 112 113clauses(Cs, Env) -> 114 clauses(Cs, none, Env). 115 116clauses([C | _] = Cs, Else, Env) -> 117 Vs = new_vars(cerl:clause_arity(C), Env), 118 E = match(Vs, Cs, Else, add_vars(Vs, Env)), 119 {E, Vs}. 120 121%% The implementation very closely follows that described in the book. 122 123match([], Cs, Else, _Env) -> 124 %% If the "default action" is the atom 'none', it is simply not 125 %% added; otherwise it is put in the body of a final catch-all 126 %% clause (which is often removed by the below optimization). 127 Cs1 = if Else =:= none -> Cs; 128 true -> Cs ++ [cerl:c_clause([], Else)] 129 end, 130 %% This clause reduction is an important optimization. It selects a 131 %% clause body if possible, and otherwise just removes dead clauses. 132 case cerl_clauses:reduce(Cs1) of 133 {true, {C, []}} -> % if we get bindings, something is wrong! 134 cerl:clause_body(C); 135 {false, Cs2} -> 136 %% This happens when guards are nontrivial. 137 cerl:c_case(cerl:c_values([]), Cs2) 138 end; 139match([V | _] = Vs, Cs, Else, Env) -> 140 foldr(fun (CsF, ElseF) -> 141 match_var_con(Vs, CsF, ElseF, Env) 142 end, 143 Else, 144 group([unalias(C, V) || C <- Cs], fun is_var_clause/1)). 145 146group([], _F) -> 147 []; 148group([X | _] = Xs, F) -> 149 group(Xs, F, F(X)). 150 151group(Xs, F, P) -> 152 {First, Rest} = splitwith(fun (X) -> F(X) =:= P end, Xs), 153 [First | group(Rest, F)]. 154 155is_var_clause(C) -> 156 cerl:is_c_var(hd(cerl:clause_pats(C))). 157 158%% To avoid code duplication, if the 'Else' expression is too big, we 159%% put it in a local function definition instead, and replace it with a 160%% call. (Note that it is important that 'is_lightweight' does not yield 161%% 'true' for a simple function application, or we will create a lot of 162%% unnecessary extra functions.) 163 164match_var_con(Vs, Cs, none = Else, Env) -> 165 match_var_con_1(Vs, Cs, Else, Env); 166match_var_con(Vs, Cs, Else, Env) -> 167 case is_lightweight(Else) of 168 true -> 169 match_var_con_1(Vs, Cs, Else, Env); 170 false -> 171 F = new_fvar("match_", 0, Env), 172 Else1 = cerl:c_apply(F, []), 173 Env1 = add_vars([F], Env), 174 cerl:c_letrec([{F, cerl:c_fun([], Else)}], 175 match_var_con_1(Vs, Cs, Else1, Env1)) 176 end. 177 178match_var_con_1(Vs, Cs, Else, Env) -> 179 case is_var_clause(hd(Cs)) of 180 true -> 181 match_var(Vs, Cs, Else, Env); 182 false -> 183 match_con(Vs, Cs, Else, Env) 184 end. 185 186match_var([V | Vs], Cs, Else, Env) -> 187 Cs1 = [begin 188 [P | Ps] = cerl:clause_pats(C), 189 G = make_let([P], V, cerl:clause_guard(C)), 190 B = make_let([P], V, cerl:clause_body(C)), 191 cerl:update_c_clause(C, Ps, G, B) 192 end 193 || C <- Cs], 194 match(Vs, Cs1, Else, Env). 195 196%% Since Erlang is dynamically typed, we must include the possibility 197%% that none of the constructors in the group will match, and in that 198%% case the "Else" code will be executed (unless it is 'none'), in the 199%% body of a final catch-all clause. 200 201match_con([V | Vs], Cs, Else, Env) -> 202 case group_con(Cs) of 203 [{_, _, Gs}] -> 204 %% Don't create a group type switch if there is only one 205 %% such group 206 make_switch(V, [match_congroup(DG, Vs, CsG, Else, Env) 207 || {DG, _, CsG} <- Gs], 208 Else, Env); 209 Ts -> 210 Cs1 = [match_typegroup(T, V, Vs, Gs, Else, Env) 211 || {T, _, Gs} <- Ts], 212 make_switch(V, Cs1, Else, Env) 213 end. 214 215 216match_typegroup(_T, _V, Vs, [{D, _, Cs}], Else, Env) when element(1, D) /= ?binary_id -> 217 %% Don't create a group type switch if there is only one constructor 218 %% in the group. (Note that this always happens for '[]'.) 219 %% Special case for binaries which always get a group switch 220 match_congroup(D, Vs, Cs, Else, Env); 221match_typegroup(T, V, Vs, Gs, Else, Env) -> 222 Body = make_switch(V, [match_congroup(D, Vs, Cs, Else, Env) 223 || {D, _, Cs} <- Gs], 224 Else, Env), 225 typetest_clause(T, V, Body, Env). 226 227match_congroup({?binary_id, Segs}, Vs, Cs, Else, Env) -> 228 Body = match(Vs, Cs, Else, Env), 229 cerl:c_clause([make_pat(?binary_id, Segs)], Body); 230 231match_congroup({D, A}, Vs, Cs, Else, Env) -> 232 Vs1 = new_vars(A, Env), 233 Body = match(Vs1 ++ Vs, Cs, Else, add_vars(Vs1, Env)), 234 cerl:c_clause([make_pat(D, Vs1)], Body). 235 236make_switch(V, Cs, Else, Env) -> 237 cerl:c_case(V, if Else =:= none -> Cs; 238 true -> Cs ++ [cerl:c_clause([new_var(Env)], 239 Else)] 240 end). 241 242%% We preserve the relative order of different-type constructors as they 243%% were originally listed. This is done by tracking the clause numbers. 244 245group_con(Cs) -> 246 {Cs1, _} = mapfoldl(fun (C, N) -> 247 [P | Ps] = cerl:clause_pats(C), 248 Ps1 = sub_pats(P) ++ Ps, 249 G = cerl:clause_guard(C), 250 B = cerl:clause_body(C), 251 C1 = cerl:update_c_clause(C, Ps1, G, B), 252 D = con_desc(P), 253 {{D, N, C1}, N + 1} 254 end, 255 0, Cs), 256 %% Sort and group constructors. 257 Css = group(keysort(1, Cs1), fun ({D,_,_}) -> D end), 258 %% Sort each group "back" by line number, and move the descriptor 259 %% and line number to the wrapper for the group. 260 Gs = [finalize_congroup(C) || C <- Css], 261 %% Group by type only (put e.g. different-arity tuples together). 262 Gss = group(Gs, fun ({D,_,_}) -> con_desc_type(D) end), 263 %% Sort and wrap the type groups. 264 Ts = [finalize_typegroup(G) || G <- Gss], 265 %% Sort type-groups by first clause order 266 keysort(2, Ts). 267 268finalize_congroup(Cs) -> 269 [{D,N,_}|_] = Cs1 = keysort(2, Cs), 270 {D, N, [C || {_,_,C} <- Cs1]}. 271 272finalize_typegroup(Gs) -> 273 [{D,N,_}|_] = Gs1 = keysort(2, Gs), 274 {con_desc_type(D), N, Gs1}. 275 276%% Since Erlang clause patterns can contain "alias patterns", we must 277%% eliminate these, by turning them into let-definitions in the guards 278%% and bodies of the clauses. 279 280unalias(C, V) -> 281 [P | Ps] = cerl:clause_pats(C), 282 B = cerl:clause_body(C), 283 G = cerl:clause_guard(C), 284 unalias(P, V, Ps, B, G, C). 285 286unalias(P, V, Ps, B, G, C) -> 287 case cerl:type(P) of 288 alias -> 289 V1 = cerl:alias_var(P), 290 B1 = make_let([V1], V, B), 291 G1 = make_let([V1], V, G), 292 unalias(cerl:alias_pat(P), V, Ps, B1, G1, C); 293 _ -> 294 cerl:update_c_clause(C, [P | Ps], G, B) 295 end. 296 297%% Generating a type-switch clause 298 299typetest_clause([], _V, E, _Env) -> 300 cerl:c_clause([cerl:c_nil()], E); 301typetest_clause(atom, V, E, _Env) -> 302 typetest_clause_1(is_atom, V, E); 303typetest_clause(integer, V, E, _Env) -> 304 typetest_clause_1(is_integer, V, E); 305typetest_clause(float, V, E, _Env) -> 306 typetest_clause_1(is_float, V, E); 307typetest_clause(cons, _V, E, Env) -> 308 [V1, V2] = new_vars(2, Env), 309 cerl:c_clause([cerl:c_cons(V1, V2)], E); % there is no 'is cons' 310typetest_clause(tuple, V, E, _Env) -> 311 typetest_clause_1(is_tuple, V, E); 312typetest_clause(binary, V, E, _Env) -> 313 typetest_clause_1(is_binary, V, E). 314 315typetest_clause_1(T, V, E) -> 316 cerl:c_clause([V], cerl:c_call(cerl:c_atom('erlang'), 317 cerl:c_atom(T), [V]), E). 318 319%% This returns a constructor descriptor, to be used for grouping and 320%% pattern generation. It consists of an identifier term and the arity. 321 322con_desc(E) -> 323 case cerl:type(E) of 324 cons -> {?cons_id, 2}; 325 tuple -> {?tuple_id, cerl:tuple_arity(E)}; 326 binary -> {?binary_id, cerl:binary_segments(E)}; 327 literal -> 328 case cerl:concrete(E) of 329 [_|_] -> {?cons_id, 2}; 330 T when is_tuple(T) -> {?tuple_id, tuple_size(T)}; 331 V -> {?literal_id(V), 0} 332 end; 333 _ -> 334 throw({bad_constructor, E}) 335 end. 336 337%% This returns the type class for a constructor descriptor, for 338%% grouping of clauses. It does not distinguish between tuples of 339%% different arity, nor between different values of atoms, integers and 340%% floats. 341 342con_desc_type({?literal_id([]), _}) -> []; 343con_desc_type({?literal_id(V), _}) when is_atom(V) -> atom; 344con_desc_type({?literal_id(V), _}) when is_integer(V) -> integer; 345con_desc_type({?literal_id(V), _}) when is_float(V) -> float; 346con_desc_type({?cons_id, 2}) -> cons; 347con_desc_type({?tuple_id, _}) -> tuple; 348con_desc_type({?binary_id, _}) -> binary. 349 350%% This creates a new constructor pattern from a type descriptor and a 351%% list of variables. 352 353make_pat(?cons_id, [V1, V2]) -> cerl:c_cons(V1, V2); 354make_pat(?tuple_id, Vs) -> cerl:c_tuple(Vs); 355make_pat(?binary_id, Segs) -> cerl:c_binary(Segs); 356make_pat(?literal_id(Val), []) -> cerl:abstract(Val). 357 358%% This returns the list of subpatterns of a constructor pattern. 359 360sub_pats(E) -> 361 case cerl:type(E) of 362 cons -> 363 [cerl:cons_hd(E), cerl:cons_tl(E)]; 364 tuple -> 365 cerl:tuple_es(E); 366 binary -> 367 []; 368 literal -> 369 case cerl:concrete(E) of 370 [H|T] -> [cerl:abstract(H), cerl:abstract(T)]; 371 T when is_tuple(T) -> [cerl:abstract(X) 372 || X <- tuple_to_list(T)]; 373 _ -> [] 374 end; 375 _ -> 376 throw({bad_constructor_pattern, E}) 377 end. 378 379%% This avoids generating stupid things like "let X = ... in 'true'", 380%% and "let X = Y in X", keeping the generated code cleaner. It also 381%% prevents expressions from being considered "non-lightweight" when 382%% code duplication is disallowed (see is_lightweight for details). 383 384make_let(Vs, A, B) -> 385 cerl_lib:reduce_expr(cerl:c_let(Vs, A, B)). 386 387%% --------------------------------------------------------------------- 388%% Rewriting a module or other expression: 389 390%% @spec expr(Expression::cerl(), Env) -> cerl() 391%% Env = rec_env:environment() 392%% 393%% @doc Rewrites all <code>case</code>-clauses in 394%% <code>Expression</code>. <code>receive</code>-clauses are not 395%% affected. 396%% 397%% <p>The environment is used for generating new variables which do not 398%% shadow existing bindings.</p> 399%% 400%% @see clauses/2 401%% @see rec_env 402 403-ifndef(NO_UNUSED). 404-spec expr(cerl:cerl(), rec_env:environment()) -> cerl:cerl(). 405 406expr(E, Env) -> 407 case cerl:type(E) of 408 binary -> 409 Es = expr_list(cerl:binary_segments(E), Env), 410 cerl:update_c_binary(E, Es); 411 bitstr -> 412 V = expr(cerl:bitstr_val(E), Env), 413 Sz = expr(cerl:bitstr_size(E), Env), 414 Unit = expr(cerl:bitstr_unit(E), Env), 415 Type = expr(cerl:bitstr_type(E), Env), 416 cerl:update_c_bitstr(E, V, Sz, Unit, Type, cerl:bitstr_flags(E)); 417 literal -> 418 E; 419 var -> 420 E; 421 values -> 422 Es = expr_list(cerl:values_es(E), Env), 423 cerl:update_c_values(E, Es); 424 cons -> 425 H = expr(cerl:cons_hd(E), Env), 426 T = expr(cerl:cons_tl(E), Env), 427 cerl:update_c_cons(E, H, T); 428 tuple -> 429 Es = expr_list(cerl:tuple_es(E), Env), 430 cerl:update_c_tuple(E, Es); 431 'let' -> 432 A = expr(cerl:let_arg(E), Env), 433 Vs = cerl:let_vars(E), 434 Env1 = add_vars(Vs, Env), 435 B = expr(cerl:let_body(E), Env1), 436 cerl:update_c_let(E, Vs, A, B); 437 seq -> 438 A = expr(cerl:seq_arg(E), Env), 439 B = expr(cerl:seq_body(E), Env), 440 cerl:update_c_seq(E, A, B); 441 apply -> 442 Op = expr(cerl:apply_op(E), Env), 443 As = expr_list(cerl:apply_args(E), Env), 444 cerl:update_c_apply(E, Op, As); 445 call -> 446 M = expr(cerl:call_module(E), Env), 447 N = expr(cerl:call_name(E), Env), 448 As = expr_list(cerl:call_args(E), Env), 449 cerl:update_c_call(E, M, N, As); 450 primop -> 451 As = expr_list(cerl:primop_args(E), Env), 452 cerl:update_c_primop(E, cerl:primop_name(E), As); 453 'case' -> 454 A = expr(cerl:case_arg(E), Env), 455 Cs = expr_list(cerl:case_clauses(E), Env), 456 {E1, Vs} = clauses(Cs, Env), 457 make_let(Vs, A, E1); 458 clause -> 459 Vs = cerl:clause_vars(E), 460 Env1 = add_vars(Vs, Env), 461 G = expr(cerl:clause_guard(E), Env1), 462 B = expr(cerl:clause_body(E), Env1), 463 cerl:update_c_clause(E, cerl:clause_pats(E), G, B); 464 'fun' -> 465 Vs = cerl:fun_vars(E), 466 Env1 = add_vars(Vs, Env), 467 B = expr(cerl:fun_body(E), Env1), 468 cerl:update_c_fun(E, Vs, B); 469 'receive' -> 470 %% NOTE: No pattern matching compilation is done here! The 471 %% receive-clauses and patterns cannot be staged as long as 472 %% we are working with "normal" Core Erlang. 473 Cs = expr_list(cerl:receive_clauses(E), Env), 474 T = expr(cerl:receive_timeout(E), Env), 475 A = expr(cerl:receive_action(E), Env), 476 cerl:update_c_receive(E, Cs, T, A); 477 'try' -> 478 A = expr(cerl:try_arg(E), Env), 479 Vs = cerl:try_vars(E), 480 B = expr(cerl:try_body(E), add_vars(Vs, Env)), 481 Evs = cerl:try_evars(E), 482 H = expr(cerl:try_handler(E), add_vars(Evs, Env)), 483 cerl:update_c_try(E, A, Vs, B, Evs, H); 484 'catch' -> 485 B = expr(cerl:catch_body(E), Env), 486 cerl:update_c_catch(E, B); 487 letrec -> 488 Ds = cerl:letrec_defs(E), 489 Env1 = add_defs(Ds, Env), 490 Ds1 = defs(Ds, Env1), 491 B = expr(cerl:letrec_body(E), Env1), 492 cerl:update_c_letrec(E, Ds1, B); 493 module -> 494 Ds = cerl:module_defs(E), 495 Env1 = add_defs(Ds, Env), 496 Ds1 = defs(Ds, Env1), 497 cerl:update_c_module(E, cerl:module_name(E), 498 cerl:module_exports(E), 499 cerl:module_attrs(E), Ds1) 500 end. 501 502expr_list(Es, Env) -> 503 [expr(E, Env) || E <- Es]. 504 505defs(Ds, Env) -> 506 [{V, expr(F, Env)} || {V, F} <- Ds]. 507-endif. % NO_UNUSED 508%% @clear 509 510%% --------------------------------------------------------------------- 511%% Support functions 512 513new_var(Env) -> 514 Name = env__new_vname(Env), 515 cerl:c_var(Name). 516 517new_vars(N, Env) -> 518 [cerl:c_var(V) || V <- env__new_vnames(N, Env)]. 519 520new_fvar(A, N, Env) -> 521 Name = env__new_fname(A, N, Env), 522 cerl:c_var(Name). 523 524add_vars(Vs, Env) -> 525 foldl(fun (V, E) -> env__bind(cerl:var_name(V), [], E) end, Env, Vs). 526 527-ifndef(NO_UNUSED). 528add_defs(Ds, Env) -> 529 foldl(fun ({V, _F}, E) -> 530 env__bind(cerl:var_name(V), [], E) 531 end, Env, Ds). 532-endif. % NO_UNUSED 533 534%% This decides whether an expression is worth lifting out to a separate 535%% function instead of duplicating the code. In other words, whether its 536%% cost is about the same or smaller than that of a local function call. 537%% Note that variables must always be "lightweight"; otherwise, they may 538%% get lifted out of the case switch that introduces them. 539 540is_lightweight(E) -> 541 case get('cerl_pmatch_duplicate_code') of 542 never -> cerl:type(E) =:= var; % Avoids all code duplication 543 always -> true; % Does not lift code to new functions 544 _ -> is_lightweight_1(E) 545 end. 546 547is_lightweight_1(E) -> 548 case cerl:type(E) of 549 var -> true; 550 literal -> true; 551 'fun' -> true; 552 values -> all(fun is_simple/1, cerl:values_es(E)); 553 cons -> is_simple(cerl:cons_hd(E)) 554 andalso is_simple(cerl:cons_tl(E)); 555 tuple -> all(fun is_simple/1, cerl:tuple_es(E)); 556 'let' -> (is_simple(cerl:let_arg(E)) andalso 557 is_lightweight_1(cerl:let_body(E))); 558 seq -> (is_simple(cerl:seq_arg(E)) andalso 559 is_lightweight_1(cerl:seq_body(E))); 560 primop -> 561 all(fun is_simple/1, cerl:primop_args(E)); 562 apply -> 563 is_simple(cerl:apply_op(E)) 564 andalso all(fun is_simple/1, cerl:apply_args(E)); 565 call -> 566 is_simple(cerl:call_module(E)) 567 andalso is_simple(cerl:call_name(E)) 568 andalso all(fun is_simple/1, cerl:call_args(E)); 569 _ -> 570 %% The default is to lift the code to a new function. 571 false 572 end. 573 574%% "Simple" things have no (or negligible) runtime cost and are free 575%% from side effects. 576 577is_simple(E) -> 578 case cerl:type(E) of 579 var -> true; 580 literal -> true; 581 values -> all(fun is_simple/1, cerl:values_es(E)); 582 _ -> false 583 end. 584 585 586%% --------------------------------------------------------------------- 587%% Abstract datatype: environment() 588 589env__bind(Key, Val, Env) -> 590 rec_env:bind(Key, Val, Env). 591 592-ifndef(NO_UNUSED). 593%% env__bind_recursive(Ks, Vs, F, Env) -> 594%% rec_env:bind_recursive(Ks, Vs, F, Env). 595 596%% env__lookup(Key, Env) -> 597%% rec_env:lookup(Key, Env). 598 599%% env__get(Key, Env) -> 600%% rec_env:get(Key, Env). 601 602%% env__is_defined(Key, Env) -> 603%% rec_env:is_defined(Key, Env). 604 605env__empty() -> 606 rec_env:empty(). 607-endif. % NO_UNUSED 608 609env__new_vname(Env) -> 610 rec_env:new_key(Env). 611 612env__new_vnames(N, Env) -> 613 rec_env:new_keys(N, Env). 614 615env__new_fname(F, A, Env) -> 616 rec_env:new_key(fun (X) -> 617 S = integer_to_list(X), 618 {list_to_atom(F ++ S), A} 619 end, 620 Env). 621