$_ takes each value of **@B**, since it's grep {...} @B
@A = (1, 4, 7, 10, 14);
@B = (1, 3, 2, 4);
@seen{@A} = ();
# does:
# $seen{ 1} = undef;
# $seen{ 4} = undef;
# $seen{ 7} = undef;
# $seen{10} = undef;
# $seen{14} = undef;
@C = grep { !exists($seen{$_}) } @B;
# In the grep evaluator, $_ takes the value of each
# element of argument list, one at a time.
#
# !exists($seen{1}) evaluates to false (undef).
# !exists($seen{3}) evaluates to true (1).
# !exists($seen{2}) evaluates to true (1).
# !exists($seen{4}) evaluates to false (undef).
#
# grep returns the values that resulted in true,
# so the result is:
# @C = (3, 2);
@merged = (@A, @C);
# @merged = (1, 4, 7, 10, 14, 3, 2);
# @A--------------- ----@C
|