Wednesday, July 25, 2012

Haskell is poorly explained

WARNING: The article below was written in a passionate wave of anger over Haskell's ponderous learning curve. I know it's logic is flawed. However, I am confident that plenty of other Haskell newbs have encountered the same issues and are also banging their head into the wall.  Since this section of the blog is about Haskell from the learner's perspective, I have decided to publish it now, and edit the salient points at a later date when the smoke of my ignorance has cleared:
 
     Most of the problems listed here (I suspect) are a result of poor documentation by all of the resources I have used so far. Having said that...

     Yes, it's true Haskell is a functional language, and as a result should not be held too strictly to the tenets of competing non-fp languages like, say ohhh, Python for instance. Python is a superbly easy language to learn from scratch (with zero CS background), and can do just about anything a programmer would ever need to do in the current professional environment. Haskell, is one of many candidates for a new ubiquitous general programming schema (functional programming) which may one day supplant the older imperative programming paradigm. In order for FP to push programming into a new direction and solve the current set of programming limitations, it needs to also do the simple things at least as well, if not better than, the current selection of popular general-purpose languages. Indeed, for it even to be considered a general-purpose language, it needs to excel at the basic level.  As such, it is assumed that Haskell (and any other good implementation of FP) can do things other languages can't do very easily or very well. It is also assumed that it will take some getting used to in order to master FP having come (as 99% of every coder on the planet has) from an imperative programming environment.

     I've been trying to keep this in mind as I develop my attitude towards Haskell as a learner and petty blogger. The problem is that this is not a valid excuse for the many problems facing anyone attempting to learn Haskell without a full-time professor, teacher's aid, or tutor on hand. I personally have begun to use freenode #haskell in lieu of such a resource. But, that is not an ideal solution. The people on #haskell are wise and generous, but they have no obligation to patiently explain things to a frustrated learner. They do so anyways (because they rock), but the IRC format itself forces all but the most blunt and carefree of folks to limit their inquiries for fear of being flamed or banned as a niuscance.

     So, that's no big deal, a good text can change all that. Haskell doesn't have a good text. But I am starting to realize, that is not the sole issue either. I am not a cultural relativist. I believe, scratch that, I know that there are some human behaviours that are right and some that are wrong. It doesn't matter if Functional Programming is based on a totally different way of thinking about problem-solving (which it isn't), there are some basic user-interface considerations that are universal and have nothing to do with the structure of the programming environment. Haskell defies some of these most basic considerations:

  • Inconsistent Syntax between interactive environments and compiler. Commands and declarations that work on Hugs don't always work on ghci and vice-versa. Commands that work in ghci and Hugs in interactive mode do not always compile. This is dumb. Plain and simple. There is no excuse. There is no point trying out program snippets in an interactive environment that gives totally different results from the compiler. That just defeats the point of even having an interactive environment. IDLE exemplifies how this can be done correctly.
  • Conflicting rules based on still more hidden laws. In Chapter 2 of Haskell: The Craft of Functional Programming we are asked to create a module which loads yet another module and uses it's code as a basis for new functions. We have previously been told that indentation is optional in Haskell. We have also been told that indentation is really just a way to make the contents of a function easier to read; and can be dispensed with at will. However, the only way to import a function inside of the definition of another function is to indent the import command, like this:                                                                                                              >module name where                                                                                                                     >    import oldmodule  
  • IO what a mess... Yes, I know Haskell IO is based on Monads which are themselves an attempt to separate impure data from pure data. Fine, I get it. But, can we at least get a listing of the reasons behind the ponderous IO mentality at work here? For example: We are told that IO actions have to be performed within a function which is, itself, an IO action. We are also told that IO actions cannot be called outside of the 'main = do' function. Then we realize (I have yet to see this documented anywhere) that certain IO actions (like getLine) cannot be called inside of 'main'. In order to bring data in from the outside world, we need to create seperate functions, each with their own 'do' notations and then call them from main. However, main handles output operations like putStrLn just fine. Why? Likewise, we are told that main, and all other 'do' notation functions must end with a function or command that returns data. Yet, some functions or commands mysteriously don't work, despite meeting all of the qualifications needed. Other functions that do work return no data whatsoever except null (). Why the inconsistency? Then there's print. Print works sometimes and then fails spectacularly at others. And, it should'nt be about type; since print has the capability to display data of all built-in types from Ints to Bools. You eventually learn to use print sometimes and putStrLn at others; often without knowing why. Why is this so hard?!
  • 'let' it be already... Declaring a variable is one of the most universal processes that occur in programming. It's the core function. In Haskell, you say 'let x = whatever'. The only problem is that let doesn't always work. For instance, try declaring a list in hugs. 'let x = [1,2,3]' doesn't work. 'x = [1,2,3]'? Nope. How the hell do you declare a stupid list? Yes, there is a way, but who cares? Why do we need to learn a 3rd way to declare a list in Hugs? We shouldn't even need to learn two ways to declare a simple variable. There should only be 1! In the time it takes to figure this out, you could be making list comprehensions in Python that already work!
  • Pointless compiler reports that even professors can't understand Why bother? If you can create a logically consistent compiler output then you can also link it to a simple pattern-matching algorithm (perhaps using Haskell's own pattern-matching toolset) that gives the user some information that is actually useful. Most of the compiler errors I have run across fall into one of four categories: 1) A function is missing an argument 2) You used the wrong type for some function or operation 3) You are missing an indent (even though indents are supposed to be voluntary). 4) You are missing parens somewhere. What's the point of even having error-messages when even the experts have a hard time understanding them?
     My point is simple: Haskell is not ready for prime-time. I'm at the point where I must choose to continue studying Haskell even though my gut is telling me that the designers never intended the language to actually be used. Thanks to LYAH, I have seen some of the ways in which Haskell can be exceptionally powerful compared to what I'm used to (Python and C++). I also know that I am an undergrad and my opinion will change once I gain mastery of the language. As a result, I am resolved to continuing my study of Haskell. 

    Still, I can already see why the language is doomed to obscurity in it's current state. It will need either massive ergonomic reform, or an exceptionally bright text to overcome it's pointlessly steep learning curve.


Thursday, July 12, 2012

Why programming has never really caught on...

Wait, I know what you're thinking


     "Is this guy retarded or something? Programming is a multi-billion dollar business! Of course it's caught-on!" That's not what I mean. Sure there are thousands of professional coders out there, and millions of end-users (OK probably closer to billions). But, why don't those end-users code? The closest we, as a society, came to utilizing the power of programming en masse was the HTML/CSS boom of the early 2000s. Now, thanks to wordpress and scores of other turnkey solutions, that boom is in the rear view. Why aren't average schmoes coding?

     The reason has to do with symbolic leveraging. This is a cognitive phenomenon that occurs with any language; human or otherwise. The point behind symbolic leverage is that a symbol only has meaning if the reader has a built-in association for it. A good example is the Indus Valley Script. The civilization who read that script is extinct. So, the language is now useless. To make matters worse, the language was highly developed -- not like hieroglyphs whose meaning could often be gleaned by sight alone. The IVS symbols are highly abstracted (like the Arabic script used in English). The more highly abstracted a symbol (or programming module) is, the more useless it is to the uninitiated. 

     The IVS leverages it's symbols on information that already exists in the user's mind. This allows it to quickly cover massive amounts of highly complex concepts with an economy of words. This is great for the lazy writer, and horrible for the student. In the case of written 'natural languages' (there's no such thing -- but that's another story), this only works in generalized societies with institutionalized rules which attempt to enforce equality and freedom of property-rights. After all, why spend your hard-earned money to train slaves or indentured servants to read when they can't own property and will only ever do manual labor.  

     In our own world society, this has only been the case for about 150 years (in some places far far less) out of a recorded history of about 7000 years and a biological history of about 500,000. Amazingly enough, the bulk (some believe over 80%) of the last 500,000 years seem to have been spent without verbal language! In the historical past, only the rich had the time and resources to hire a teacher to decode their own written language for their education; and that was usually because their caste depended on property exchanges  -- which are encoded in written language -- to maintain their status. Even then, it took up years upon years of the human student's most prodigious period of learning to achieve this: childhood. In short, language itself is a pretty recent invention!

     Now enter computer languages: most are less than 20 years old, most are not taught to the public, and ALL rely on symbolic leveraging to a degree that has never been known in the history of humanity. Even the modern math that computer languages are based on is less than a century old. Add to that the fact that computer languages are typically written by mathematicians and engineers; those people on planet earth with the absolute WORST of communication skills and by far the greatest amount of abstract symbols with which to leverage their new -- impossibly terse -- computer language.

     The reason why this is a problem can be best explained in computer programming terms. In computer science, the programmer who chooses to write a program which discretely solves all possible problems a user can throw at him (brute-force programming) is called a schmuck. A good programmer, instead, creates declarative rules for problem solving, then creates a form of artificial intelligence which can use those rules to solve each new problem as it occurs. Unfortunately, they never apply this principle to the structure of the programs they create. As a result, each stand-alone program is itself just a discrete collection of responses to all the foreseeable problems the user can throw at it. Ironically, we coders continue to find ever newer and more abstract techniques of using complex declarative rules to create a solution which, in and of itself, is merely a discrete collection of 'canned' responses to a shockingly limited amount of inputs. 

     As a result, the average user has no idea how to automate even the simplest of tasks on his computer. The language of automation is so obfuscated with entropic jargon and arbitrary syntax inspired by abstruse flights of mathematical fancy, that he would need to devote a minimum of four years to his life (at the expense of all his other activities) in order to gain the knowledge needed to make his computer do what it was supposed to be doing for us all along. The only way we know to solve this conundrum is by paying a coder way too much money to come along and give us a handful more 'canned responses' which themselves are impossible to automate for the end-user. And so the cycle continues.

     The reason why the natural language programming paradigm won't die (no matter how much it is demeaned by pro coders) is that it offers a way to do just that; to increase the intelligence of the computers we end-users use and unleash the truest power of the computer -- the power to automate. Until coders change the way they think about coding, computers will never reach the next level. Each new OS will look more and more like the last one and the role of the CS pro will begin to diminish instead of increase. It's already starting to happen. Think about how little progress has occurred between Windows XP and 8, OSX Tiger and Lion, Ubuntu 10 and 13.

     The future of commercial programming is natural language processing and it's bosom-buddy: AI. We need to start using the programming language as a way, not only to create powerful and economical abstractions, but as also as a way to begin absorbing the burden of symbolic leveraging instead of placing it entirely on the programmer. It's already happening; just witness the astronomical growth of Python and the cutting edge Go project from Google. We have reached the limits of our capability to deal with abstractions effectively, this is why Haskell will never really catch-on, and why Lisp never really did. 

     Imagine a world where we use the computer, not just to gossip with friends and send messages to one agency or another, but where the computer is an extension of your body; your will. The computer will be like an open-source personal secretary. Freed from repetitive monotonous tasks, the end-user will be allowed to a lot their development time towards specializing in that most noble professional niche; creativity. We will be free to apply our mind to tasks that really matter to our human survival in ways that only humans can do using our imaginations. In terms of creative vision, that beats the crap out of Facebook! 

The Inherent Intelligence Principle

Figure it out on your own!


     There is a well-meaning tendency for technical and educational authors to over-explain certain details to the extreme that they actually obfuscate what would otherwise be a simplistic subject. This is an artifact of technical writing which comes from a sense of diligence and thoroughness. Any good technical writer knows that it is crucial to cover as many steps as possible in the explanation of complex instructions.

     However, a good technical writer also knows that the average reader is able to piece certain things together on her own, which saves the writer time and allows the student a little breathing room in what would otherwise be a stiflingly slow read. The problem then becomes, how do I know what material to cover and what to 'gloss-over'? Most writers just make intuitive guesses, for better or worse, and chalk it up to a 'hazard of the trade'.

     Thankfully, this is an unnecessary compromise. There is a shockingly simple and organic way to allow the reader to decide on her own. It requires a more modern way of thinking about technical text and the employment of an idea which is unique to the information age: the hyperlink. And no, you don't need a computer to implement this technique, although it certainly helps simplify the process.

     In many ways, the qualities that make a good technical writer are much the same as those that make a good parent. That is, a good parent shows her children the behaviour that she expects from them, instead of constantly telling them. For instance, if a good parent wants their child to be quiet in public places, then she herself will endeavor to be consistently quiet in public places. Contrast this to the parent who stomps around Walmart yelling at her children over the slightest of offenses and then subsequently yells at her children when they talk too loudly and generally make an embarrassing scene. Kids don't care half as much about what you tell them to do as what you yourself are doing. 

     With this analogy in mind, take the subject if an introduction to Haskell. One of the first (if not the first) things you learn in any programming class is basic IO. There are a number of logical reasons for this which extend beyond tradition; basic IO is essentially what all programs do, at some level or another. A program is an abstract computational device which takes data in from the outside world, processes it, and spits it back out. In order to begin programming (which is the only way to really learn a programming language), you need to understand IO. Once you do, you can create a nearly infinite selection of programs using only a basic understanding of that program's primitives.

     The problem is, Haskell was written by sadists who believe that basic IO is a second class function of computer programming. Don't get me wrong, I like Haskell quite a bit. But, how do you teach computer programming with a language which fervently resists the input and output of data at every turn? 

     What most writers have done so far with Haskell, is show you everything else you can do with Haskell first, and save basic IO for the intermediate stages of the course. This is a HUGE mistake. There simply aren't that many practical programs which can be built without some form of IO. As a result, most Intro to Haskell books have little to no assigned practice work. For instance, Learn You a Haskell, Real World Haskell, and the Intro to Haskell Wikibook: A Gentle Introduction to Programming with Haskell. This goes against all established educational theory concerning Computer Science. In order for a student to gain any thing more than anecdotal knowledge of a new programming language, they must spend more time coding it than reading it.* The reason why authors make this mistake is that explaining Haskell IO to the uninitiated is pretty difficult. However, you don't need to explain everything in order to give a Haskell newb a working knowledge; and therein lies the problem. 

     Humans have an innate understanding of language hard-wired into their gray matter. The main way in which we learn new human languages is through exposure and by differentiating context. That is, we learn multiple ways to say something and deduce the meanings of those slight differences in expression automatically. This natural process of deduction is the foundation of logic and lives in the same spot of gray matter as language itself.  Nobody tells a baby "This is the word 'Mommy': it means the person who feeds you." The baby would never learn if that were the case (due to the Primum Movens paradox). By this same mental process, you can present Haskell IO to Intro students from the get go.

     When they come to some irreducibly complex element of your explanation ( a 'roadblock' ) they can then either click a hyper-link featuring gradually more detailed explanations or flip to the correct page in your manual for elaboration on the sticky subject. 

Here's an example. We want to introduce the student to Haskell IO and assume that the student has no prior CS experience. This should be the only approach when teaching a new language, regardless of the student's level of indoctrination -- see my article on scaffolding**. Here's the didactic text:


     1) Let's display "Hello World" in your computer's terminal:

     Prelude> putStrLn "Hello World"
     Hello World

     1b) Now display a warm-fuzzy phrase of your choice in the terminal

     Prelude> putStrLn "I like Haskell!"
     I like Haskell!

     Here the student just learned that putStrLn is the command for displaying strings onscreen without  being told a thing about it or how it works or what a string is.

     2) Now let's get some information from the person sitting at the keyboard (you) and put it into ghci. Enter this phrase and type  your name at the following prompt.

     Prelude> getLine
     ryan
     "ryan"

     2b) Now get your age and print it onscreen.

     Prelude> getLine
     20
     "20"

   
     Yes these are over-simplifications (for your sake), but the principle is evident and it holds at all higher-levels. A reader doesn't need to be told anything at all about putStrLn, they can look at it, mentally elminate Hello World from their reasoning (because it is the message and thus not the method for displaying said message) and see then that the only remaining commands are putStrLn and "".

  • The user knows that quotations marks are used to display exactly what a person said or is being instructed to say. They will also see that the quotation marks do not appear in the onscreen output. They will have no choice but to deduce that quotation marks are expected when entering a command into putStrLn. So, they usually know to use quotation marks again in the 1b problem. If not, they can just click on the hyperlinked-word putStrLn and be presented with a note explaining this explicitly.
  • They also already know that capital letters are only used at the beginning of a new proper or formal word. So, they know that putStrLn has to be a concatenation of put+str+ln. Even if they don't know what str and ln mean, they know what put means. They will immediately connect put with the fact that they are currently trying to put some data onto the display before them. Since you showed them that this is indeed what putStrLn does, they know to use if for this. 9 times out of 10, they will correctly perform exercise 1b. The same goes for getLine and many more basic commands.
  • By using the same command on two different types of data (letters and numbers) the student now knows that getLine can be used for multiple things; not just for names. All this without mentioning a thing about 'types'.
 
      As I am slowly writing my own Intro to Haskell, you will see better examples of this principle later on. But for now, with a little imagination, you should see that it is also possible to leverage information that exists in every persons brain in order to explain difficult concepts. This is Vigotsky's principle of scaffolding and it's utility in CS should be apparent now. If not, check in from time to time. This is a theme I will be writing on often.

*For a good contrast to this recipe for didactic failure, check out MIT Open Course-Ware's Introduction to Computer Science using Python: Introduction to Computer Science and Programming

**That article is currently still pending.

Sunday, July 8, 2012

Emerge the Hive Mind

     Most creative people know this feeling: you've been nursing an idea in the back of your mind for years or even decades. Maybe it's a widget or some academic discovery you haven't had time to properly write-up. Then one day, you take a break and turn on the boob-toob and whadaya see? Someone on the other side of the country (or world)  is introducing your idea and reaping heaps of praise for it's ingeniousity! What a bummer! Then you have to go back to your stupid job waiting-tables and cursing progress for not waiting on your brilliance

     This has happened to me too many times to count; one day I'll write them all down (he he). However, I know now not to be angry about it. History is actually full of these sorts of synchronous discoveries. The perfect example is Leibniz and Newton.

     If you have ever taken a Calculus class, you know how ridiculously improbable it seems that anyone would invent Calculus in two separate places, unknown to each other, at exactly the same time*. I mean talk about the limits of human understanding, Calculus is right there -- straddling the borderline. How could two people think of the same sadistic way to torture undergraduates at exactly the same time?

     Well, it happens all the time. There is a perfectly good reason for this. There are no truly individual discoveries. All discoveries are built on the pool of knowledge available to the people of a time. For example, if you went back in time 2000 years ago and gave the standard IQ test to everyone you met on your travels, your results would illustrate that everyone you met is a mongoloid, and should probably be put in an insane asylum. Of course, they aren't mongoloids. Knowledge is encrusted upon a civilization in a very delicate way that is not unlike how mineral deposits form stalactites. The pool of knowledge for that era just hasn't had the time or resources to encrust the necessary conceptual tools needed to return a passing score on our stupid 20th century IQ test. However, once the requisite information is in the public consciousness, discoveries are inevitable.

     Our population and information-technology is so highly developed now, that people have created a live, real-time hive-mind. It doesn't really matter who ends up writing that paper on the idea you had. After all, if you had the resources ten years ago, you would have written it before her. The point is that the idea be expressed using the scientific methods and conceptual frameworks in existence in such a way as to resist logical attack long enough to enter the public consciousness and make a change for the good.

     In order to advance past the current messy state of human progress, we need to focus, not on who had the idea first, but on whether we were able to prove or disprove it using the terminology and theoretical framework of Science.

    Our need to create heroes to worship is a uniquely western fascination. We have tricked ourselves into believing that everyone can be a hero if they just meet the right people and work hard enough. This is hogwash. Improving the human condition is not unlike improving an unhappy relationship. The only thing that will help is if we each 'work on our shit'. That is to say, we each know what our faults are. If you want to make improvements in life, as in society, you need to start doing the things you know you should have been doing all along. Take the trash out, tell your loved-ones you love them, and stop worshiping heroes. They are just people who 'worked on their shit' enough to garner the fickle adoration of the masses.

     If we forget about the need to find new heroes we may actually break down the academic wall that prevents ideas like the one you had ten years ago from being popularized. This is the idea behind Open Source. And contrary to the beliefs of the entire academic community (up until the last 15 years), it works! Open Source took the entire mainstream academic world by surprise. It only gets stronger every day. This is the emergence of the hive-mind in micro scale. Millions of people all around the world who have let go of their need to be heroes or billionaires and submitted their work for all to use, rip off and forget to cite.

      Long live the hive mind!

*OK, it didn't happen quite like that but, my point still stands.

The Western Way to Learn

As mush as possible, as fast as possible...


     There is a very silly book out there by Paramahansa Yogananda that introduced me to a unique revelation about the western way of learning. I won't waste my time quoting it verbatim, but the idea was that westerners learn each subject as quickly as possible, almost as if this were all some big race. Of course, they never really learn the subject at all. 

     The Indian way of learning was presented by way of example: when an Indian is taught the Vedas, he is taught each verse over and over until it becomes an unforgettable unit of his mental processes. Only then does the instructor move on to the next verse (never mind the next chapter). The end result is that the student can recite the Ramayana by memory, unbroken, as easily as if he were asking you for a glass of water. 

     This is no doubt an example of Vedic hyperbole (or maybe not), but it hits at an important point. Westerners rush our education with disastrous consequences. We zoom through the subject matter in record time without ever really understanding it or, worse yet, knowing how to use it. I know this to be true in my gut as I'm sure any reader will. Yet, as a person who hates rote memorization with an ugly passion, how to address this shortcoming?

     My solution is to reduce all of the underlying techniques of each discipline into some combination of fundamental scientific, linguistic, or mathematical principles -- using a common terminology. Then, as I learn new subjects and rehash the old ones, I submit myself to a more endurable form of rote memorization. Each time it feels new, yet each lesson is composed of ideas I know well already. This creates problems. First of all, how do I describe complex and subtle artistic ideas in universal (often mathematical) terms. Also, as I do this, I must discard the entropic terminology of the art-form in question and substitute my own. As a result, professionals in the field have no idea what I'm talking about should I choose to converse. 

     Besides, this is a slow process and bedeviling to the nth degree. I still haven't realized enough of this declarative language to publish a lexicon or method to teaching it. Nonetheless, progress occurs and I find myself retaining a little bit more and more with every effort. It makes logical sense and it seems to be working. It's a work in progress and I resign myself to being called a crackpot in the meantime. But hopefully not in the same league of crackpot as the aforementioned writer. 

Knowledge-Retention

or 'Aww, what was that thing called?'


     I have a confession to make, I'm a drifter. Well, not the handkerchief-at-the-end-of-a-stick kind of drifter (although I've done that too), I mean I'm an intellectual drifter. I have a lifelong obsession with learning new skills which I will probably never use. Once I understand the underlying principles at work in a new skill or art form, I immediately lose interest and move on to something else. 

    This is not even half as cool as it sounds. I'm already approaching middle-age, nearly broke, and I don't have much to show for my obsession other than some cool stories. No really, this is pathological in my case. I have changed majors so many times that my relatives no longer wince when they ask me "so what are you doing these days?" They just know it's going to be some outlandish answer which will change in a year. I already have about four years in school and still no degree. I have over 80 credits and no freakin' degree* (as of this writing at least).

     However, there is one crucial lesson I would never have learned otherwise; most experts never actually learn how to learn. They just internalize a set of behaviors until it becomes something akin to 'muscle-memory'. This always irritated the hell out of me. Once I fully understood music theory (back when I was a music major), I also then realized that great performers were just people who sat in their room all day and repeated the same mind-numbing exercises until their hands 'knew what to do'. I couldn't imagine a more boring existence, never mind the astronomical odds against a musician ever making a dime in her profession. Still, I can confidently say that I know how to learn better than most of my professors ever will.

     So, when I inevitably move on to some new field of study, I can't help but notice how quickly the hard-won knowledge I gained disappears. I'm no genius, but I'd say I have an above-average intelligence. I have discipline-for-days, an organized mind, and undying tenacity. So, imagine my shock at seeing that information slip away from me in days -- not even months or years, DAYS. I used to be able rattle off every inversion of every chord, letter name by letter name at will. I could sit down with a circuit-diagram and find the Thevenin Equivalence by hand within minutes. Now, I barely remember what Thevenin Equivalence even means. And no, I don't drink, smoke, box, or do anything else which could be construed as self-destructive.

     Thus, I have begun a crusade to retain all knowledge I currently gain, and reclaim all of the knowledge and skills I have lost over the years. This crusade has forced me to realize a central truth of education: most of the crap we teach ourselves and our students gets forgotten faster than it was learned. I'm talking record time. Ask any math-teacher about what happens immediately after summer-break every year of their career. Sadly, only the brightest and best retain enough knowledge to actually absorb new material throughout the semester. Most average students just play catch-up all year long and graduate with passing-grades and only a tentative understanding of the subject at hand. 

     Add to this the fragmented format in which math and most other subjects are taught, and you have a recipe for, well, America's public school system. 

     Currently, my method to defeat this innate human tendency is to find the underlying principles behind every course of study I have undergone so far and formalize it into one declarative language of ideas. Then, each new subject I learn is really just a refresher course with some unique discreet applications in theory. Flashcards, extensive notes and this blog itself are my primary weapons against Information Overload while I develop UP in the dark. I think it is working, but only time will tell. 

     This new method has opened me up to UL and ultimately spawned Universal Primitivism.  It only works with practice though, and there is so much work to do with no guidebook on how to do it. Still, I foresee most people thinking this idea of UP is idealist or even silly, with good reason I suppose. But maybe if you understand why I'm doing it, you will find it is not silly or idealist at all, in fact it is purely pragmatic because it comes from a very real challenge I undergo every day: me versus my memory.

*All 80 credits with straight-As mind you! Well, unless you count those two Bs in Music Theory, man those were hard classes!

     

The Limits of Human Understanding



     Contrary to popular belief, there is a very real limit to what humans can understand in real time. Sure, we can build new theories out of old theories and publish them to great effect. But, in terms of real-time, moment to moment operation, humans are very limited in their capacity to carry out complex chains of instructions.

     In other words, academia has long since outlived it's direct usage to that average human. In order for us to gain the fruits of state-of-the-art science, a for-profit corporation (like Microsoft) has to come along and develop Applications with a user-interface that falls squarely within the attention-span of the average human. Scientists are just as susceptible to this phenomenon as brick-layers (just look at the sales for Mathmatica and Matlab). Nobody is exempt.

     Computer scientists simply create new abstractions and sell them as "Apps". This is the grand totality of all human knowledge made tangible. If we simply accept this limitation in momentary human awareness, we can begin to make progress in education. For instance, if we know the area limits of a subject wherein the concepts involved are starting to become so complex that people have ceased to use them publicly (Algebra: do you still know what an imaginary number is?), then we need only design the next group of abstractions to address those operations on the outer limits using some intuitive interface.

     A good (if oversimplified) example of this is the nines tool. You should know this, but I'll repeat it for argument's sake: Nine times any single digit number is equal to the next lowest integer in front of the number needed to create nine: 9 * 8 = 72. The next lower number from 8 is 7 and the number needed to create 9 with 7 is 2. Therefore, 9 * 8 = 72. This intuitive leveraging tool allows us to internalize some of the more difficult operations and devote our momentary awareness to the next plateau of concepts; in this case memorization of multiplication tables. Instead of fighting our limitations, accept them and layer our approach to education and knowledge creation around them.

     The pressure of routine life and death decisions can create some startling pragmatic observations. For instance, the military (specifically the Air Force) has known about the limits of human understanding for a long time now. They even have a phrase for it, "task saturation". They also invented the popular term "information overload". They now know that abstractions need to be employed in an intuitive way in order to keep their pilots alive. The academic world can take a lesson from them.

     After all, there are only so many ways a person can interact with the world around them. Thankfully, all but the world's most mind-boggling processes can be represented in visual or tactile ways that require a minimal amount of effort from the student (or jet pilot). The problem is finding these analogues and employing them in a consistent way. A good starting point would be to incorporate the types of ideas found in books like Arthur Benjamin's Secrets of Mental Math into primary school education. Of course, most of the problems a computer scientist deals with are well beyond mental math. But, there are always easier ways to solve a problem that do not involve symbolic rigor. For example, when you first approach systems of linear equations in a college algebra class, it can be a little overwhelming. There are different approaches to solving the problem using algebraic manipulation of symbolic notation. However, the easiest way of all is to plot each line and see where they all intersect. There are tricks like this at all levels of mathematics. We need only to take advantage of them.

     For my purposes, just accepting these limitations is useful in and of itself. It means that students are allowed to think about programming in terms of what they know, and not in terms of whatever Latin-inspired symbolism is being espoused by the popular culture of the times.

The Current State of Introductory Computer Science


Outline


There are basic programming primitives which an introductory student faces; regardless of the language you want to learn. For instance, you need to create variables and assign them values like numbers or words (strings). Then, you need lists of numbers or words (etc) with which you can populate, depopulate and test for membership. You also need to perform operations on them like addition or subtraction.

These core primitives form a toolbox with which you can create programs that do important tasks with mechanically perfect execution. This is the same regardless of the language.

Once you learn to master the basic primitives, you can perform all sorts of useful and interesting (even artistic) functions on just about any language platform. Yes, of course there are dizzying heights of complexity which can be reached (in shockingly different ways) with each discrete language. But, those concepts are of no use to you, the beginner. In fact, teaching them at this stage will only make your life hell. Why should you try to understand what a Monad is if you don't even know what a conditional statement is?

This doesn't stop authors and professors from shoving these ideas down your throat. To their credit, they are beneficently trying to introduce you to difficult concepts early on; so that you have so much familiarity with them that, by the time you actually need to use these concepts, you intuitively apply them to solve tricky problems.

The problem is that the human mind just doesn't work that way. In truth, humans aren't too good at dealing with symbolic abstraction (like sigma or delta etc). Ironically, the greatest scientific minds of all times belong to rebels who chose instead to 'visualize' complex abstractions in ways that made sense to them but were still mathematically useful -- think Einstein's thought experiments.

All an abstraction is, is a way to encapsulate a series of complex operations into a 'black box' which we can use without worrying about the intricate details of it's operation.

However, when mathematical symbolism is employed, the exact opposite happens. The student is confronted with what looks like an alien language which works in mysterious ways and is only ever explained using yet more self-aggrandizing academic symbolic terminology designed to prove the author's intellectual command of language and NOT to educate.

Here's an exaggerated example of poorly used symbolic terminology. Say you're a rock guitarist. A mathematician (were she writing a peer-reviewed paper on Electronic Dynamics Control Systems in the neighboring room) would tell you that you need to conscientiously modulate your low-voltage transducer output using a logarithmic potentiometer in series with your high-z output rectification stage. However, a fellow musician would simply say, "Hey man, turn your axe down!" Both sentences say the same thing. However, the first one is precise to the point of facetiousness. The other gets the same abstract point across in universal terminology that also provides some nice visualizations; a guitar does actually look a bit like a battle axe, when you adjust the volume knob it does get turned and the sound does seem to go down; from any observer's vantage. 

This is not merely a trivial argument designed to inflame anti-academic sentiment, it really does point out a salient commandment in academic writing: teachers should always seek to explain things in the most intuitive way possible. There is no logical place for abstruse verbiage in the education system unless it increases the student's intuitive understanding of the subject at hand.

The pointlessly confusing word-choices in academic instruction today are designed to ensure that the author is published on merit of their own 'literary expertise' and have no didactic use whatsoever. It is the stated goal of UP to end this shameful practice formally.

With this in mind, I will introduce the primitives to the student first. Show them how to use these primitives in a (initially limited) set of popular languages. When the primitives themselves begin to diverge widely in their language's handling, only then will I introduce new theoretical structures and then only to explain the difference in their application. The depth of the student's understanding of the language will grow organically in as much as the student is required to understand in order to accomplish universal programming tasks, and no more.

There is a glut of literature on the market explaining all of the most mind-bendingly complex subjects in Computer Science and disturbingly little covering all of the myriad useful tasks that can be accomplished using only the basics. Basic programming tasks like file I/O and merge-sorting have become so hopeless ensconced in techno-babble that many students drop-out altogether before they even learn to use them.

This creates a disconnect between author, student and teacher. Only students who are already indoctrinated in the academic material have any hope at progress in CS (and most other sciences). This is, to put it in academic terms, ass-backwards. Yet, it ensures that tenured professors continue to procure publishing contracts and speaking engagements; which is why it dominates educational literature.

In summary, you will learn about the byzantine abstract mechanization underlying your chosen programming language only when you need to; and then only in the most intuitive and useful way possible. If every level of CS education were instructed in this way*, there would be more CS graduates and more advancements in the field. Professors would no longer have sole authority on the subjects they teach! I wonder why this approach hasn't caught on yet?

*Of course there are a handful (just a handful) of fine books out there that manage to do this very elegantly. CSS: The Missing Manual by David Sawyer McFarland is a shining example and an inspiration to aspiring technical writers like me.

What do you mean by primitive?


     The term primitive is, I hate to admit, one of those self-aggrandizing academic terms. However, it's use is justified. There aren't many other words in computer science that have the intuitive connotations and verbal flexibility of the word primitive. After all, a primitive can be both a noun and an adjective. It summons imagery of a rag-bedecked cave man throwing a rock at a passing antelope. This is useful imagery!

     A primitive is just a basic building block. It's a completely relative term. It also helps you understand that computer programs are layered like an onion. If you are looking at the outer most layer of an onion which sits in a pile of other onions about to be sweated into a French Onion Soup, that particular onion looks like one irreducible building block of the soup. But, of course, an onion has a bewildering amount of layers beneath the one you are looking at.

     Computer languages are written in other computer languages, which themselves are written in other computer languages, which themselves are eventually written in binary code, which itself is an arbitrary (processor-specific) language that is composed of things like op-amps, memory and counter ICs which are themselves arbitrary arrangements of transistors. Transistors are strange little devices that take advantage of the strange behavior of elements like silicon, germanium, and phosphor to produce a simply massive amount of effects which are so confusing that most programmers have simple no idea how they work. Hell, even if you understand how one type of transistor works pretty well, there are literally thousands more that work in completely different ways! Is this starting to sound familiar in any way?

     This is actually a lot like one of Mandelbrot's fractals. That is, you see this layered construction, wherein each layer does the same sort of thing as the one above it, but in increasingly complex modalities which themselves get harder and harder to understand. This is the genesis behind my idea of a Fractal Programming Language: If these layer's are unavoidable, why not give them one coherent topology and syntax which covers all the necessary primitives needed to build programs of any level of complexity. Then, each layer of programming consists of the same set of core primitives, with new functions created (out of the layers below) to deal with ever-increasing levels of abstraction?

     OK, now that your brain is spinning, back to primitives. Just think of primitives as basic ingredients with which you can 'cook' up new recipes.