Simple Natural Language Parser in Objective-C - objective-c

I'm building this app for Mac OS X v10.6
I'm building a text-based adventure and I've created a very simple natural language parser that can process the commands that the user types. So far it works great and can parse sentences such as: "take the sword" or "look in the box"
What I'm trying to do is create a list of aliases for different words to make typing commands less strict. So for example "take" could have an alias of "grab" or "go" could have the aliases "move, walk, or travel"
I've tried creating an NSDictionary where the key was the word and the value was an NSArray of aliases. The problem was that when determining if the command entered matched an available command, I would have to reference the aliases with the word that was used for the key.
I want to be able to use any of the aliases to reference any of the other aliases. Does anyone know of a good way to do that?
Another thought I had (but it seems to inefficient) is to store each set of aliases in an array. When parsing I would find the array that contains the word I want to match and try to match all the other words in that array against it.

Check NSLinguisticTagger class (new in iOS 5)

Conceptually, I think you might find it productive to treat all words on the same footing. Let your dictionary have any word from your vocab as a key, and the value numerically encode the interpretation or information that guides interpretation in context.

It works also for OS X http://cutecoder.org/programming/introduction-cocoa-nslinguistictagger-nsbrief-podcast-72/ and check out https://github.com/adib/ColorizeWords

Related

Custom, user-definable "wildcard" constants in SQL database search -- possible?

My client is making database searches using a django webapp that I've written. The query sends a regex search to the database and outputs the results.
Because the regex searches can be pretty long and unintuitive, the client has asked for certain custom "wildcards" to be created for the regex searches. For example.
Ω := [^aeiou] (all non-vowels)
etc.
This could be achieved with a simple permanent string substitution in the query, something like
query = query.replace("Ω", "[^aeiou]")
for all the elements in the substitution list. This seems like it should be safe, but I'm not really sure.
He has also asked that it be possible for the user to define custom wildcards for their searches on the fly. So that there would be some other input box where a user could define
∫ := some other regex
And to store them you might create a model
class RegexWildcard(models.Model):
symbol = ...
replacement = ...
I'm personally a bit wary of this, because it does not seem to add a whole lot of functionality, but does seem to add a lot of complexity and potential problems to the code. Clients can now write their queries to a db. Can they overwrite each other's symbols?
That I haven't seen this done anywhere before also makes me kind of wary of the idea.
Is this possible? Desirable? A great idea? A terrible idea? Resources and any guidance appreciated.
Well, you're getting paid by the hour....
I don't see how involving the Greek alphabet is to anyone's advantage. If the queries are stored anywhere, everyone approaching the system would have to learn the new syntax to understand them. Plus, there's the problem of how to type the special symbols.
If the client creates complex regular expressions they'd like to be able to reuse, that's understandable. Your application could maintain a list of such expressions that the user could add to and choose from. Notionally, the user would "click on" an expression, and it would be inserted into the query.
The saved expressions could have user-defined names, to make them easier to remember and refer to. And you could define a syntax that referenced them, something otherwise invalid in SQL, such as ::name. Before submitting the query to the DBMS, you substitute the regex for the name.
You still have the problem of choosing good names, and training.
To prevent malformed SQL, I imagine you'll want to ensure the regex is valid. You wouldn't want your system to store a ; drop table CUSTOMERS; as a "regular expression"! You'll either have to validate the expression or, if you can, treat the regex as data in a parameterized query.
The real question to me, though, is why you're in the vicinity of standardized regex queries. That need suggests a database design issue: it suggests the column being queried is composed of composite data, and should be represented as multiple columns that can be queried directly, without using regular expressions.

Many instances of a terminal symbol in a BNF grammar

given a grammar like
<term>::= x[i]+exp(x[i]) | x[i]
<i>::= 1|2|3
Does a way exist to force the use of the same "i" in one solution of non terminal symbol ? So, I want to avoid solutions like x[1]+exp(2) or x[3]+exp(1)
Does a way exist to avoid that the same "i" is used in one solution of non terminal symbol ?So, I want to avoid solutions like x[1]+exp(1)
No, that's not possible with a context-free grammar.
This is essentially what "context-free" means. Every non-terminal in a production can be expanded independently without regard to the context in which it appears.
Of course, if i really only has three possible values, you can enumerate the finite number of legal productions, according to any definition of "legal" which you find convenient. But that gets really messy when the number of possibilities increases.
The most convenient solution is generally to accept the base syntax and check for concordance (or difference) in the associated semantic rule. That also allows for better error messages.

Is using comma separated field good or not

I have a table named buildings
each building has zero - n images
I have two solutions
the first one (the classic solution) using two tables:
buildings(id, name, address)
building_images(id, building_id, image_url)
and the second solution using olny one table
buildings(id, name, address, image_urls_csv)
Given I won't need to search by image URL obviously,
I think the second solution (using image_urls_csv column) is easier to use, and no need to create another table just to keep the images, also I will avoid the hassle of multiple queries or joining.
the question is, if I don't really want to filter, search or group by the filed value, can I just make it CSV?
On the one hand, by simply having a column of image_urls_list avoids joins or multiple queries, yes. A single round-trip to the db is always a plus.
On the other hand, you then have a string of urls that you need to parse. What happens when a URL has a comma in it? Oh, I know, you quote it. But now you need a parser that is beyond a simple naive split on commas. And then, three months from now, someone will ask you which buildings share a given image, and you'll go through contortions to handle quotes, not-quotes, and entries that are at the beginning or end of the string (and thus don't have commas on either side). You'll start writing some SQL to handle all this and then say to heck with it all and push it up to your higher-level language to parse each entry and tell if a given image is in there, and find that this is slow, although you'll realise that you can at least look for %<url>% to limit it, ... and now you've spent more time trying to hack around your performance improvement of putting everything into a single entry than you saved by avoiding joins.
A year later, someone will give you a building with so many URLs that it overflows the text limit you put in for that field, breaking the whole thing. Or add some extra fields to each for extra metadata ("last updated", "expires", ...).
So, yes, you absolutely can put in a list of URLs here. And if this is postgres or any other db that has arrays as a first-class field type, that may be okay. But do yourself a favour, and keep them separate. It's a moderate amount of up-front pain, and the long-term gain is probably going to make you very happy you did.
Not
"Given I won't need to search by image URL obviously" is an assumption that you cannot make about a database. Even if you never do end up searching by url, you might add other attributes of building images, such as titles, alt tags, width, height, etc, so you would end up having to serialize all this data in that one column, and then you would not be able to index any of it. Plus, if you serialize it with one language, then you or whoever comes after you using a different language will either have to install some 3rd party library to deserialize your stuff or write their own deserialization function.
The only case that I can think of where you should keep serialized data in a database is when you inherit old software that you don't have time to fix yet.

Underscores or camelCase in PostgreSQL identifiers, when the programming language uses camelCase?

This has been bothering me for a while, and I can't arrive at a solution that feels right...
Given an OO language in which the usual naming convention for object properties is camelCased, and an example object like this:
{
id: 667,
firstName: "Vladimir",
lastName: "Horowitz",
canPlayPiano: true
}
How should I model this structure in a PostgreSQL table?
There are three main options:
unquoted camelCase column names
quoted camelCase column names
unquoted (lowercase) names with underscores
They each have their drawbacks:
Unquoted identifiers automatically fold to lowercase. This means that you can create a table with a canPlayPiano column, but the mixed case never reaches the database. When you inspect the table, the column will always show up as canplaypiano - in psql, pgadmin, explain results, error messages, everything.
Quoted identifiers keep their case, but once you create them like that, you will always have to quote them. IOW, if you create a table with a "canPlayPiano" column, a SELECT canPlayPiano ... will fail. This adds a lot of unnecessary noise to all SQL statements.
Lowercase names with underscores are unambiguous, but they don't map well to the names that the application language is using. You will have to remember to use different names for storage (can_play_piano) and for code (canPlayPiano). It also prevents certain types of code automation, where properties and DB columns need to be named the same.
So I'm caught between a rock and a hard place (and a large stone; there are three options). Whatever I do, some part is going to feel awkward. For the last 10 years or so, I've been using option 3, but I keep hoping there would be a better solution.
I'm grateful for any advice you might have.
PS: I do realize where the case folding and the need for quotes is coming from - the SQL standard, or rather PostgreSQL's adaptation of the standard. I know how it works; I'm more interested in advice about best practices than explanations about how PG handles identifiers.
If your columns in the PostgreSQL are with underscores, you can put aliases but with doule-quotes.
Example :
SELECT my_column as "myColumn" from table;
Given that PostgreSQL uses case-insensitive identifiers with underscores, should you change all your identifiers in your application to do the same? Clearly not. So why do you think the reverse is a reasonable choice?
The convention in PostgreSQL has come about through a mix of standards compliance and long-term experience of its users. Stick with it.
If translating between column-names and identifiers gets tedious, have the computer do it - they're good at things like that. I'm guessing almost all of the 9-million database abstraction libraries out there can do that. If you have a dynamic language it'll take you all of two lines of code to swap column-names to identifiers in CamelCase.
I know this is late however for something that would be simple to translate on the fly, you could write a small help function that would live in your code as such:
function FormatObjForDb(srcObj){
const newObj = {};
Object.keys(srcObj).forEach(key => newObj[key.toLowerCase()] = srcObj[key]);
return newObj;
}
export const formatObjForDb = FormatObjForDb;

Why are many languages case sensitive?

Why are many languages case sensitive?
Is it simply a matter of inheritance? C++ is case-sensitive because C is, Java is case-sensitive because C++ is, etc.? Or is there a more pragmatic reason behind it?
I don't think you'll get a better answer than "because the author(s) of that language thought it was better that way". Personally, I think they're right. I'd hate to find these lines anywhere in the same source file (and refer to the same object+method)...
SomeObject.SomeMethod();
...
SOMEOBJECT.SOMEMETHOD();
...
someObject.someMethod();
...
sOmEoBjEcT.sOmEmEtHoD();
I don't think anyone would be happy to see this...
Unix.
Unix was case sensitive, and so many programming languages developed for use on Unix were case sensitive.
Computers are not forgiving - an uppercase character is not the same thing as a lowercase character, they're entirely different. And back when processing cycles, RAM and so forth were expensive it wasn't seen as worth the effort to force compilers and computers to be "forgiving", people were just trying to get the things to work.
Notice how case insensitivity didn't really become something useful until things like Visual Basic came along - once companies started to get invested in the concept that getting the masses to program was a good thing for their bottom line (i.e., Microsoft makes more money if there're more programs on Windows) did the languages start to be friendlier and more forgiving.
One interesting thing to consider is that English is also case-sensitive. (I suspect this is true for most natural languages, but it may well not be true for all.)
There's a big difference (where I live, anyway, near the town of Reading) between:
I like reading.
and
I like Reading.
Similarly, while many people do capitalise incorrectly, and you can usually understand what is meant, that doesn't mean such writing is considered correct. I'm a stickler when it comes to this kind of thing, which is not to say I get everything right myself, of course. I don't know whether that's part of the inheritance of programming language case sensitivity, but I suspect it may be.
One distinct advantage of case sensitivity for programming languages is that the text becomes culturally insensitive as well. It's bad enough having to occasionally spell out to a compiler which text encoding is used for a source file - having to specify which culture it's in would be even worse :(
It's actually extremely practical, both for the developer and for the language syntax specification: lower/upper case distinction adds a great deal of expressiveness to identifier naming.
From the point of view of the language syntax, you can force certain identifiers to start with a lower or upper case (for instance Java class name). That makes parsing easier, and hence helps keeping the syntax clean.
From a developer point of view, this allows for a vast number of convenient coding conventions, making your code clearer and easier to understand.
My guess would be that case sensitivity enlarges the name space. A nice trick such as
MyClass myClass;
would be impossible with case-insensitive compiler.
Case folding is only simple in English (and for all characters < 128). The German sz or "sharp s" (ß) doesn't have an upper case variant in the ISO 8859-1 charset. It only received one in Unicode after about a decade of discussion (and now, all fonts must be updated...). Kanji and Hiragana (Japanese alphabets) don't even know lower case.
To avoid this mess, even in this age of Unicode, it is not wise to allow case folding and unicode identifiers.
ExpertSexChange
I believe this is a competitor to Stack Overflow where you have to pay to read answers. Hmm... with case insensitivity, the meaning of the site's name is ambiguous.
This is a good reason for languages being case-sensitive. Less ambiguity! Ambiguity to programmers is considered yucky.
Back when parsing and compiling was real expensive and would take all night it was advantageous to the compiler if it didn't have to worry about case.
Once identifiers came in to existence that were only unique via their case it became very difficult to go back. Many developers liked it and there doesn't seem to be a big desire to undo it.
Case sensitivity adds to language readability by the use of naming conventions. You can't write
Person person = new Person("Bill");
if your language is case insensitive, because the compiler wouldn't be able to distinguish between the Class name and the variable name.
Also, having Person, person, PersoN, PeRsOn, and PERSON, all be equivalent tokens would give me a headache. :)
What is the capital form of i? I (U+0049) or İ (U+0130)?
Capitalization is locale dependent.
Because they're as dumb as a box of frogs, for precisely the reasons given for the opposite viewpoint in this thread (I'm not even gonna ask what that's about. Wood for the trees and all that).
When FOOBAR = FooBar = foobar, you get to choose your convention, and other coders can do the same whether they share your preference or not. No confusion.
They also can't get away with the stroke of genius that is having a constant, function and variable all with the same name in the same file, albeit with different caps. Again, no confusion.
You call your variable WebSite, they call theirs Website, and which system gets confused? Not an easy catch either, when you're scanning.
As for lookups, is it really that much more processing to convert the name to lowercase before looking it up? Doing your own premature optimisation is one thing, expecting it from the developer of your language of choice is a whole other level of missing the point.
...and yet, all these answers saying case-sensitivity reduces confusion. Sigh
Many (non-programming) languages (e.g. European using the Roman alphabet) are case-sensitive, so it's natural for native speakers of those languages to use upper- / lower-case distinctions.
The very idea that programming languages wouldn't be case-sensitive is a historical artifact arising from the limitations of early-generation hardware (including pre-computer teletype machines that used a 5-bit character code).
People who argue for case-blind languages must be unable to distinguish
IAmNowHere
from
IAmNowhere
(It's a joke! ;-)
There's also Common Lisp, which is a case-sensitive language that many people mistakenly believe is case-insensitive. When you type (car x) into the Listener, it turns into (CAR X) for processing. It is possible to define symbols with lower-case names, but they have to be quoted with something like |lower-case-symbol|. Therefore, typing in (car x) or (CAR X) or (Car X) all works the same.
(Franz Lisp was at one point introducing what they called "modern" capitalization, in which the Listener would not fold cases, and CL keywords would be in lowercase. I never followed it well enough to know what happened there.)
The upper-case of a letter isn't a universal concept. Java uses Unicode, so if you wanted case-insensitive Java, the meaning of your program could change depending on what locale it was compiled in.
Most languages don't let you put dots or commas (or apostrophes or spaces) in the middle of integer literals, probably because that's also locale-dependent.
From
.NET Framework Developer's Guide
Capitalization Conventions, Case-Sensitivity:
The capitalization guidelines exist
solely to make identifiers easier to
read and recognize. Casing cannot be
used as a means of avoiding name
collisions between library elements.
Do not assume that all programming
languages are case-sensitive. They are
not. Names cannot differ by case
alone.
How do you yell if you don't HAVE CAPS?! AHHH!
You have to be expressive. But in all honesty, of all the people in the world, those who work with programming logic would be the first to insist that differences are in fact differences.
I have read this entire thread. I must believe that those that report to have found value in case sensitivity have never programmed in a true high level language (which by definition is case insensitive). K&R admit that C is mid-level. After programming in Pascal, Delphi, Lazarus, ADA, etc, one learns that highly readable code is simple to write and to get to run quickly without obsessing on terse case sensitive constructs. After all, readability is the first and last word on the subject. Code is written for the human, not the computer. No problems to debug with case insensitive code.
When one moves down to a mid-level language, one finds that there are NO advantages to case sensitivity. There are however, a considerable number of hours spent debugging case sensitivity caused problems. Especially when patching together modules from different coders.
It also appears that a large number of respondents do not understand what is meant by case insensitivity. Only the characters a-z are affected. These are a sequential subset of ASCII characters. Three or four bytes of machine code make the compiler indifferent to case in this range of characters. It does not alter under-bar, numerals, or anything else. The points about other languages and character sets simply do not apply to this discussion. The compiler or interrupter would be coded to temporarily convert or not convert the character for analysis at compile time based on the being ASCII or not.
I am shocked at the new languages like Python that have come out repeating the mistake that K&R made. Yes they saved half dozen bytes in an environment where the total RAM for compiler, source, and object code was 1000 bytes. That was then. Now Memory is not a problem. Now, for no sensible reason, even the reserve words in Python are case sensitive! I do not think I will need to use "For" of "Print" as variable or function name. But that possibility has been preserved by the expensive of the time spent contenting with the interrupter over the exact case of each identifier. A bad deal I think.
The closest thing I have read to date in support of case sensitivity is the comments on Hashing. But these rare coding events that can be handled with careful attention to detail do not seem to be to be worth the pointless scrutiny a coder must use to write case sensitive code. Two views of the problem. One encourages bad coding, set traps in the code, and requires extra attention to be diverted away from bigger concepts. The other has no down side, has worked flawlessly in high level languages, and allows flexibility were it does no harm. It looks to me like yet another case of VHS wins over BETA. It's just my two cents worth here.
Lots of people here have said that it would be bad for several forms of capitalization to refer to the same thing, e.g.:
person
perSoN
PERSON
What would be really bad is if these all referred to different objects in code. If you've got variables person, perSoN and PERSON all referring to different things, you've got a problem.
Case sensitivity doesn't really help case consistency.
Foo.Bar
foo.Bar
fOO.bAR
In a case insensitive language that can be fixed automatically by the editor easily.
In a case sensitive language fixing it it's harder as it may be legal. The editor first has to ckeck if foo.Bar and fOO.bAR exist and also has to guess that you typed with the wrong case rather than forgetting to declare the variable (as Foo is different to fOO).
Every example I've seen supporting case sensitivity is based on a desire to write bad, undescriptive code. e.g. the "date" vs. "myDate" argument - these are both equally undescriptive and bad practice. Good practice is to name it what it actually is: birthDate, hireDate, invoiceDate, whatever. And who in their right mind would want to write code like:
Public Class Person
Public Shared ReadOnly PERSON As Person
End Class
Public Class Employee
Public person As Person = person.PERSON
End Class
Amazingly this is perfectly valid case insensitive VB.Net code. The thought that case sensitivity allows you to even more flagrantly disobey good programming practice is an argument against it, not for it.
I think having a case-sensitive language ENCOURAGES people to write poor code.
Const SHOESIZE = 9
Class ShoeSize
ShoeSize.shoesize = SHOESIZE
call shoeSize(ShoeSize);
function shoeSize(SHOEsize)
{
int ShoeSIZE = 10
return ShoeSize
}
Duh. You couldn't think of a better variable name than "ShoeSize" for the different purposes? There is a billion different words you could use, but you choose to just keep using ShoeSize instead?
Because many people find employeeSocailSecurityNumber just as readable as employee_social_security_number and it is shorter.
And you could also (foolishly) just use single-letters ("a" and "b" and "c") for all classes, variables, functions, and methods.
But WHY would you want to?
Use names that make sense, not:
function a(a)
{
int a = a.a;
return a
}
By typical coding standards, Person would be a class, person a variable name, and PERSON a constant. It's often useful to use the same word with different capitalization to mean something related but slightly different.
So, if you had three staff members in your business all called Robert, you'd refer to them as Robert, robert and ROBERT would you? And rely on people to know exactly which one you meant?
Give them email addresses such as Robert#widgets.com, robert#widgets.com, and ROBERT#widgets.com if your email system was case sensitive?
The potential for an unauthorised breach of personal data would be huge. Not to mention if you sent the database root password to the disgruntled employee about to be sacked.
Better to call them Bob, Robbie, and Robert. Better still to call them Robert A, Robert B and Robert C if their surnames were e.g. Arthur, Banks, and Clarke
Really - why on earth have a naming convention that invites mistakes or confusion, that relies on people being very alert? Are you so short of words in your volcabulary?
And as for the person who mentions the supposedly handy trick "MyClass myClass" - why, why why? You deliberately make it difficult to see at a glance whether a method used is a class method or an instance method.
Plus you lost the chance to tell the next person reading your code more about the particular instance of the class.
For instance.
Customer PreviousCustomer
Customer NewCustomer
Customer CorporateCustomer
Your instance name needs to ideally tell your colleague more than just the class it's based on!
Learning is always easier by example so here it goes:
C#(case sensitive but usable from VB.NET which is case insensitive):
CONSTANT_NAME
IInterfaceName // Uses I prefix in all case sensitive and insensitive languages
ClassName // Readable in both case sensitive and insensitive languages
_classMember // sometimes m_classMember or just classMember
DoSomething(someParam) // Method with action name, params can be _someParam
PropertyName // Same style in case sensitive and insensitive languages
localVariable // Never using prefix
Java and JS use a style similar to C# but methods/functions/events are declared like variables doSomething, onEvent.
ObjectPascal(Delphi and Lazarus/FPC are case insensitive, like ADA and VB.NET)
CConstantName // One can use Def or no prefix, not a standard
IInterfaceName
TClassName // Non-atomic types/classes have T prefix e.g. TStructRecordName
PSomePointer // Pointers have types, safer low level stuff
FClassFieldMember // F means Field member similar to m
DoSomething(Parameter) // Older code uses prefix A for parameters instead
PropertyName
LLocalVariable // Older code uses prefix for parameters not local vars
Using only OneCase and prefixes for each type makes sense in all languages. Even languages that started without prefixes have newer constructs like Interfaces that don't rely on case but use a prefix instead.
So it's really not important if a language is case sensitive or not. Newer concepts were added to case sensitive languages that were too confusing to be expressed by case alone and required using a prefix.
Since case sensitive languages started using prefixes, it's only reasonable to stop using case with the same identifier name someIdentifier SomeIdentifier SOME_IDENTIFIER, ISomeIdentifier and just use prefixes where it makes sense.
Consider this problem:
You have a class member called something, a method/function parameter called something and a local variable called something, what case convention could be used to easily differentiate between these ?
Isn't it easier to just use the most ConsistentCaseStyle everywhere and add a prefix ?
Fans of case insensitive languages care about code quality, they just want one style. Sometimes they accept the fact that one library is poorly written and use a strict style while the library might have no style or poor code.
Both case sensitive and insensitive languages require strict discipline, it makes more sense to have only one style everywhere. It would be better if we had a language that used only StrictCase, one style everywhere and prefixes.
There is a lot of poor C code, case sensitivity doesn't make it readable and you can't do anything about it. In a case insensitive language you could enforce a good style in your code without rewriting the library.
In a StrictCase language that doesn't exists yet, all code would have decent quality :)
MyClass myClass;
would be impossible with case-insensitive compiler.
Or you could be smart and actually use 2 different words... that better show what you are actually trying to do, like:
MyClass myCarDesign;
Duh.
There is another reason languages are case sensitive. IDs may be stored in a hash table and hash tables are dependent on hashing functions that will give different hashes for differing case. And it may not be convenient to convert all the IDs to all upper or all lower before running them through the hash function. I came across this issue when I was writing my own compiler. It was much simpler (lazier) to declare my language as case sensitive.
If word separation is not important then why do we put spaces between words? Therefore I think that underlines between words in a name do increase readability. Also lower case with Capitalization of appropriate characters is easiest to read. Lastly, it is surely much easier if all words can be conveyed by word of mouth - "Corporate Underscore Customer" rather than "Capital C Lower Case o r p o r a t e Underscore Capital C Lower Case u s t o m e r"! - the former can be spoken 'in one's head' the latter cannot - I wonder how people who are happy with case sensitivity handle these case sensitive names in their brains - I really struggle. So I feel that case sensitivity is not at all helpfull - a retrogade step from COBOL in my opinion.
Because people seriously overthink things.
Case insensitivity works best when it's also case-preserving and combined with a separation between type and variable namespaces. This means that:
If you declare a class as 'TextureImage' and then try to use it as 'textureImage', the IDE can autocorrect you. This gives you the advantage that you'll never have to hit the shift key unless you're declaring an identifier or using an underscore.
Just like in Java and several other languages; it's perfectly valid to type "MyClass myClass". The IDE and the compiler should have no problem differentiating between the use of a type and the use of a variable.
In addition, case insensitivity guarantees that 'o' and 'O' will never refer to different objects. Common arguments include:
"sOmEoNe wIlL tYpE cOdE lIkE tHiS"; => and that someone will _never_ be allowed to join a programming team, so this is a strawman argument. even if they did manage to do so, case insensitivity is more the solution than the problem, because it means that you don't have to remember whatever crazy uppercase/lowercase combination they use.
"you can't internationalize case insensitivity easily!"; => over 95% of programming languages are written in english for a very good reason. there are no competing character encodings and the vast majority of keyboards on earth are english based (in partial or whole). supporting unicode identifiers is perhaps the dumbest idea anyone has came up with in the 21st century; because a good portion of unicode characters are frikkin invisible surragates, reading code is hard enough without having to use google translate, and writing code is hard enough without having to copy-paste identifiers or use a character map.
"but case sensitive languages have more identifiers!"; => no, they have grammatically overloaded identifiers, which is substantially worse.
I don't use any case-insensitive languages, but the advantages are blatantly obvious if you think about this sort of thing seriously.
A reasonable answer might be that the designers of the language thought it
would make the language easier to understand thinking about the future :)