The $ prefix stands for "use the value of that variable"; @ is "expand the content of the container (usually a list, but that's not the only option), and use that set of values".
For instance:
${a list}= Create List a b c
When used
FOR ${value} IN @{a list}
, is evaluated by RF as
FOR ${value} IN a b c
, which is the correct for-loop syntax.
But in the same time:
FOR ${value} IN ${a list}
, is evaluated by RF as
FOR ${value} IN ['a', 'b', 'c'] # this is a string, not an actual python list
, which is syntactically incorrect for RF.
In general, when you want to pass "the list members, each one separately" - use the @. When you need to pass the list variable itself - use the $.
This is a simplification, but covers the major use case.