Reputation: 5417
My question is related to an existing question (and boy, was I surprised to see it was a known bug in Erlang itself!). I'm using the same count_characters
example from the book, and getting the same error even though I'm on R19.
Code:
% Frequency count of characters in a string
count_characters(Str) ->
count_characters(Str, #{}).
count_characters([H|T], #{ H => N }=X) ->
count_characters(T, X#{ H := N+1 });
count_characters([H|T], X) ->
count_characters(T, X#{ H => 1 });
count_characters([], X) -> X.
and the error:
1> c(lib_misc).
lib_misc.erl:40: illegal pattern
lib_misc.erl:41: variable 'N' is unbound
error
Here line 40 refers to the first clause of count-characters/2
.
My questions are:
I can see the accepted answer on the linked page uses stuff like maps:update
. I could do the same, but I'd first like to know why the error exists.
Upvotes: 2
Views: 257
Reputation: 170745
The current error you see doesn't come from an Erlang bug. =>
is used for constructing maps, :=
for pattern matching (both are allowed for updating, the difference is that :=
only works for keys already in the map and =>
allows adding new keys). So you need :=
in the pattern:
count_characters([H|T], #{ H := N }=X) ->
% H => N+1 is also legal here, and means the same because we know H is a key of X
count_characters(T, X#{ H := N+1 });
However, after you fix this you do run into the problem: H
isn't bound yet in the #{ H := N }
pattern, and this isn't currently supported. This could be fixed by matching multiple argument patterns in order, so that H
gets bound by [H|T]
. This isn't done in R19B (at least, judging from this example) and I don't know if there are any plans to change this. It makes sense to me personally that the patterns are checked simultaneously, so I am not even sure this change would be desirable.
You can work around this by combining the first two clauses and matching X
in the body instead of the head:
count_characters([H|T], X) ->
case X of
#{ H := N } -> count_characters(T, X#{ H => N+1 });
_ -> count_characters(T, X#{ H => 1 })
end;
count_characters([], X) -> X.
Upvotes: 3