The biggest problem is that an equivalence relationship, the mathy term for things like ==
, is supposed to satisfy 3 laws.
- reflexivity,
a == a
- commutativity
a == b
means b == a
- transitivity
a == b
and b == c
means a == c
All of these are very intuitive and expected. And PHP doesn't follow them.
'0'==0 // true
0=='' // true
'0'==''// false, AHHHH
So it's not actually an equivalence relationship, which is a pretty distressing realization for some mathy people (including me).
It also hints at one of the things that people really hate about implicit casts, they often behave unexpectedly when combined with the mundane. It's basically just an arbitrary set of rules because it's unprincipled in this sense, weird stuff happens and it all needs to be specified case by case.
Basically we sacrifice consistency and the developer has to shoulder the extra burden of making sure there's no funny (and expensive) conversions happening behind the scene's. To quote this article
Language consistency is very important for developer efficiency. Every
inconsistent language feature means that developers have one more
thing to remember, one more reason to rely on the documentation, or
one more situation that breaks their focus. A consistent language lets
developers create habits and expectations that work throughout the
language, learn the language much more quickly, more easily locate
errors, and have fewer things to keep track of at once.
EDIT:
Another gem I stumbled across
NULL == 0
NULL < -1
So if you try to sort anything, it's nondetermistic and entirely dependent on the order in which comparisons are made. Eg suppose bubble sort.
bubble_sort([NULL, -1, 0]) // [NULL, -1, 0]
bubble_sort([0, -1, NULL]) // [-1, 0, NULL]
Given a closed set (fixed number of elements) S
with elements {a..z}
and a binary operator *
:
There is a single identity element i
such that:
forall x in S: i * x = x = x * i
The operator is associative such that:
forall a, b, c in S: a * (b * c) = (a * b) * c
You have a monoid.
Now given any monoid you can define a binary function f
as:
f(i, x) = x
f(x, _) = x
What this means is that for the example of the Maybe
monoid (Nothing
is the identity element denoted above as i
):
f(Nothing, Just 5) = Just 5
f(Just 5, Nothing) = Just 5
f(Just 5, Just 10) = Just 5
f(Nothing, f(Nothing, Just 5)) = Just 5
f(Nothing, f(Just 5, Nothing)) = Just 5
Surprisingly, I can't find this precise function in the default libraries, which is likely due to my own inexperience. If anyone else can volunteer this, I would sincerely appreciate it.
Here's the implementation I deduced off hand from the above example:
(<||>) :: (Monoid a, Eq a) => a -> a -> a
x <||> y
| x == mempty = y
| True = x
Example:
λ> [] <||> [1,2] <||> [3,4]
[1,2]
λ> Just "foo" <||> Nothing <||> Just "bar"
Just "foo"
λ> Nothing <||> Just "foo" <||> Just "bar"
Just "foo"
λ>
Then if you want to use a list of functions as input...
tryFunctions x funcs = foldl1 (<||>) $ map ($ x) funcs
example:
instance Monoid Bool where
mempty = False
mconcat = or
mappend = (||)
λ> tryFunctions 8 [odd, even]
True
λ> tryFunctions 8 [odd, odd]
False
λ> tryFunctions 8 [odd, odd, even]
True
λ>
Best Answer
If this is a python class, then yes, your CS teacher is correct. A number of python functions take a "comparison function" as an argument. For instance, see the sorted documentation:
How comparison functions work varies by language, though most follow a similar fashion. But since this is specifically a question about python, the answer is unambiguously "false" in that comparison functions do not always return just
True
orFalse
.