C
must be bound before the expression #{C := N}=Result
is evaluated.
You consider that C
is bound since the first parameter [C|Substring]
was evaluated before: #{C := N}=Result
. In fact it is not the case. There is no real assignment until a head evaluation succeed and the function enters the body.
Writing count_chars([C|Substring], #{C := N}=Result) ->
is exactly the same as count_chars([C1|Substring], #{C2 := N}=Result) when C1 =:= C2 ->
During the head evaluation, each element is stored in a different element (a place in the heap) to check if all the parameters match the head definition. In your case the compiler want store the value C
in an element, let's say x1 and the key C?
in another element, let's say x2, and then verify that x1 and x2 are equals. the second operation is not possible without a deep modification of the compiler behavior.
I wrote a small example to show how it works, and compiled it with the option 'S' to see the result of the compilation:
test([K|_],K,M) -> % to see how the test of parameter equality is done
#{K := V} = M, % to verify that this pattern works when K is bound.
V.
the assembly result is :
{function, test, 3, 33}.
{label,32}.
{line,[{location,"mod.erl",64}]}.
{func_info,{atom,mod},{atom,test},3}.
{label,33}.
{test,is_nonempty_list,{f,32},[{x,0}]}. % the whole list is assigned to x0
{get_hd,{x,0},{x,3}}. % the list's head is assigned to x3
{test,is_eq_exact,{f,32},[{x,1},{x,3}]}. % the second parameter K is assigned to x1, verify if x1 =:= x3
{test,is_map,{f,34},[{x,2}]}. % the third parameter M is assigned to x2, check if it is a map if not go to label 34
{get_map_elements,{f,34},{x,2},{list,[{x,3},{x,0}]}}. % get the value associated to key x3 in the map x2 and store it into x0, if no suck key go to label 34
return.
{label,34}. % throw a badmatch error
{line,[{location,"mod.erl",65}]}.
{badmatch,{x,2}}.
Now, to code your function you can simply write:
count_chars([], Result) ->
Result;
count_chars([C|Substring], Result) ->
N = maps:get(C, Result, 0) +1,
count_chars(Substring, Result#{C => N }).