That's the reason natural languages are not very well suited to formal logic, and one of the reasons programmers use programming languages.
If we reframe it using C++ "std::all_of" function over an array of strings called "hats", and say that the following must be false (because he is a liar):
std::all_of(hats.begin(), hats.end(), [](std::string hat) { return hat == "green"; })
Then we can answer the questions without ambiguity:A) The liar has at least one hat. Yes, because std::all_of returns "true" on an empty list
B) The liar has only one green hat. Unsure, because { "green", "green", "red" } is false, and { "green", "red" } is also false
C) The liar has no hats. No, it is the opposite of A
D) The liar has at least one green hat. Unsure, because { "green", "red" } is false and { "red" } is also false
E) The liar has no green hats. Unsure, for the same reason as in D
The question becomes why all_of returns true for an empty list. A better example would use std::accumulate and an 'and' function argument. The original STL documentation [1] described the function argument as having to model the Monoid[2] concept and have an identity value. The identity value for the 'and' Monoid is 'true'.
[1] https://www.boost.org/sgi/stl/MonoidOperation.html
[2] note: Monoid, not Monad, and yes, category theory left its mark in C++ as well.