SPARQL expressions use a 3-state logic: true, false and unknown. Unknown is the error-raised case. To make sure a processor only returns things known to be true, FILTER turns "unknown" into false.
For the expression;
"foo"^^xsd:string != "10"^^xsd:integer
then a minimal SPARQL 1.0 query processor is not required to know that the value spaces of xsd:string and xsd:integer are disjoint. For a processor that does not know this, the result of the comparison is "unknown" and an error is raised. If the processor did know they are disjoint, then it can return "true" -- such behavior would be adding a row to the dispatch table for functions for "xsd:string != xsd:integer".
NOT IN is value based and builds on this. If the processor understands that xsd:string and the numeric value spaces are disjoint, then it would return:
?book ?discount <http://example.org/book5> "70" <http://example.org/book3> "700.0"^^xsd:float <http://example.org/book2> 41
which is what I think you are expecting. It's the additional fact of xsd:string and xsd:integer having disjoint value spaces that is key here.
Being value based:
"700"^^xsd:float IN (500, 600, 700) is true.
Using sameTerm it would be false which might be surprising.
We would be grateful if you would acknowledge that your comment has been answered by sending a reply to this mailing list.
Andy, on behalf of the SPARQL-WG