The main reason would be intent, I suppose. If you write code that expects a list, you don’t want it to silently take binaries with unexpected results.
The description is not good enough, let me describe it another way!
Now we are redesigning Erlang, and we try to use <- on both List and Binary generators.
Since we need to generate different code for list comprehension and binary comprehension, we need a way to figure out the data type we are dealing with.
For map, we (the compiler) can see := always come with `<-`, that’s how we know it’s a map generator.
For binary, can we recognize the pattern <<…>> <- XX and treat it as binary generator?
The answer is no, because if we do that, we will never be able to handle the following situation:
For what it’s worth, I use three languages in which the equivalent of list generation is overloaded.
Haskell: [f x | x ← src, p x
Smalltalk: src collect: [:each | each] thenSelect: [:x | x p]
Pop-2: maplist(srx, lambda x; if x.p then x close end)
Haskell does this with compile-time type(class)es.
This compiles OK.
Smalltalk does it by dynamic dispatch on #collect:thenSelect:
This compiles OK.
Pop-2 does it by dynamic type checks, so overloading is not automatic.
This doesn’t lend itself to compilation to byte code.
It is very pleasant to be able to use many data types without caring
which specific type it is.
The problem with binary generators in Erlang is that you do care
because the way you match the elements is different. Being able to
iterate over a sequence of bytes is ho hum. Being able to use the
bit syntax in Erlang is important. You really do care that you can
do this.
What this means is that even at an abstract level, ← and <= in Erlang
simply mean different things. If I wanted to get the effect of <= with
bit syntax in Haskell, Smalltalk, or Erlang, it would take a lot of
extra programming.