Learn a Programming Language Faster by Copying Unix
rodrigoalvesvieira.com
rodrigoalvesvieira.com
It gets harder and harder though, to provide information about more and more distant parts of the program in a dynamically typed (or untyped) environment.
From what I've heard, Racket's contract system is another interesting attempt to provide something that's typically done in a static setting---the benefits of dependent typing---in a dynamic one.
So, the short answer is - as I thought previously - that no, you can't have implicit dispatch on return type in dynamically typed language.
Contracts are probably getting close, but you still need a version of apply that will get expected return type and a bunch of functions to introspect (or a macro that would do the same, but let's not wander there, as lispy macro systems are equivalent with static type systems anyway).
It's not quite Unix, but it's still quite lovely and it's rather succinct:
"It also contains the Plan 9 libc, libbio, libregexp, libfmt and libutf. The overall SLOC is about 66kSLOC, so this userland + all libs is much smaller than, e.g. bash (duh!)."
I believe, any well documented coding problem accompanied with a sample binary implementation should have the effective educational value.
Sites like interviewstreet.com should take this as a guide, even though their audience is not beginners. If you look at sample problems there, they are usually poorly described, and sample outputs are trivial and don't contribute to the textual description.
You also cannot zoom in, which made it very hard to read.
I'll change it. Thank you very much for reporting the problem. It now allows you to zoom in. I'll take more time to fix the header, tho.
Thanks man.
Cat is also a good example and not just to learn a programming language but the OS. Ask somebody to come up with 20 ways to display a file, you can do it with not just the cat command. Now I'm not saying there are twenty ways, but it is one area which some delving and approach will allow people to try and find them.
Examples are for me the best way to learn a programming language and again with the simple Unix commands you have a common base which people are more likely to ifnd an example. Can't recall but great site on the net which has "Hello World" in about every programming language around.
After a while, you will start to add option to your redeveloped commands, then add entirely new commands and from there you can think about writting your own shell. No graphics or the like to distract you too much. Graphics as a rule in programming languages I have found to be like learning an after thought and also you are more controlled in the mentality behind the API. So I do advise not even looking at graphics for a while until you have learned how to flex the language without the distractions graphics and the way they are handled add a overhead to your code. I'm sure somebody will list a programming language that is easier to do graphicly as apposed to text output, though its a safe rule. SO just because you have windows, don't mean you have to jump into GUI's from day one, if even at all.
http://99-bottles-of-beer.net/ http://pleac.sourceforge.net/ http://rosettacode.org/wiki/Main_Page
I honestly think that plotting per-pixel graphics is a much more fun and rewarding way to learn programming, than a cat program.
It's only a shame Linux has no "mode 13h" screen and a PSET function in the C language :)
You'll also know Linux better than most ever will.
It can be fun if you try to put your own spin on things, though with diminishing returns.
Edit: also https://github.com/darius/sketchbook/blob/master/regex/grep....
I think most people here could skim through the language intro, and then just start working on a new project in that language (picking up more of the language as they go).
This is the approach I usually use, and it seems more fun than porting the same tools. Just my opinion though :)
puts ARGF.read
I know it's besides the point, However I couldn't resist :) main = interact id
This is a slightly crude implementation of cat in Haskell. As you can see, it is replete with scary monad plumbing that gets in the way of the actual functionality (copying stdin to stdout).I would explain further and implement more than what the blog post suggested but there's already a book (Real World Haskell) that does this with a number of other Unix commands.
I just made a few more suggestions. I can't count how many neat, small tools are provided by Unix. It's a large ground to play in!
In fact, Bryan O'Sullivan (who wrote Real World Haskell) just held a tutorial session on Haskell a couple of weeks ago where people completely new to the language implemented simple Unix tools like "wc". I don't think monads were mentioned at all.
With "do" and the coincidental naming of "return", and IORefs if you insist, you can write imperative bottom-up code in Haskell.
Also, you should take a look at the top comment in this thread.
I learned C by going through the FreeBSD code and helping with POSIX compliance. For fun I would implement a lot of the commands in Python. You get the most out of learning both the language and UNIX by implementing all the command line options.
Facts can be stated in a rude manner; rude statements can be factually correct.
Asshole.
I look at the options for cat on my ubuntu system though, and realise that this problem has only gotten worse.
as PEP20 says:
Special cases aren't special enough to break the rules.
Although practicality beats purity.Also, other kinds of reuse of the things mentioned as examples of the Unix philosophy are rare. What languages on your system use lex and yacc? 'but thise tools are outdated' is not a good revuttal; if they are, how has that come about? I think the Unix philosophy is perfect for prototyping, but 'real' stuff tends to need polish that 'the unix philosophy' cannot provide. As a final example, consider git. As I understand , it started life as a set of scripts, but eventually became a C program.
Just a bit of fun, the contest doesn't seem to be very 'official'.
The project seems to be sleeping, although there are many contributions:
http://search.cpan.org/dist/ppt/Or, look up the manpage for your locally installed "tree" and see how many non-standard options and features have been bolted on.
I think it would be helpful when reimplementing Unix to try to work in more core features of the language, like its object or module system, which are more important than parsing argv or touching the filesystem.
If you were to learn Oz[1] in this manner, none of the its powerful features will be called for to implement simple filter programs, transforming text, and crashing when confused by unexpected input.
For languages that support advanced features, you're better off modeling "advanced" systems. Say, in the case of Oz, you might be better off modeling a secure microkernel or a VM; not dumb text processors.
--
Some of the code I enjoyed writing and using is, code to remember directory paths I visited (I visit lot of them, and it is a pain to type lengthy ones). A wrapper for "ssh" to remember hosts and list them (again I had to visit bunch of them daily, and pain to type fully qualified host names), just like PuTTy-saved sessions.
These tools really boost the productivity and joy to use.
[1] http://nerderati.com/2011/03/simplify-your-life-with-an-ssh-... [2] http://linux.die.net/man/5/ssh_config
For instance, what are your options on Windows or Mac? And are the languages you can do this with limited to Ruby, Python, or Javascript?
Windows doesn't have many of the basic Unix tools, but you can still implement them using your programming language of choice (how great). No, you're not limited to these three languages. I only meant in the article that these three are probably the easier to copy Unix with, for their scripting nature.
Since a Raspberry Pi is only $35 or $50 with enough stuff to program it, that is one way to get started. Of course taking an older tossed of PC and installing Linux on it works too (which can often be done for free if there are businesses around)
That's not to say the RPi isn't an interesting, rewarding experience on its own merits -- that's why I got one --, but I wouldn't recommend it to anybody interested primarily in getting a *nix environment for experimentation or programming.
As for which languages, this actually seems like it would be useful for learning any language that has reasonable ways of interacting with IO streams. Off the top of my head:
Ruby, Python, Javascript (node.js), Perl, Java, C#, Scala, Clojure, C, C++, Go, etc.
What the scripting languages give you is simplicity. No need to muss with compilers.
1. The first would be implementing your own linux commands so they work on Windows. You would probably want something like cygwin, a linux vm, or an actual linux box to test this stuff on though.
2. Pick Windows commands instead and implement them instead. It’s the same idea roughly. I haven't used a Windows machine in almost a decade, so I'm not sure what all would be involved, but seems possible that you could get them to work roughly similar.
As far as specific languages go, there’s no reason that almost any language couldn’t be used as long as it can take arguments from the command line.
On Windows you can install Linux in a virtual machine, or you can install Cygwin (which is basically an almost complete POSIX system on Windows).
You can use your preferred programming language to implement any of these tools: Ruby, Python, Perl, Scheme, Common Lisp, C, C++ ... The original Unix implementation of these tools was done in C.
[1] - http://projecteuler.net/
Indeed, for a further ego boost, why not also benchmark the performance of your versions against the performance of the native utilities? You never know, your new clone might end up being the new 'less' to the old 'more'!
I had the great pleasure, year ago in my undergrad Operating Systems class, for the class assignment to be "write an OS in Java"...which of course was handed out to a group of students who had never seen Java. By the end of the semester we had written the core guts of a multi-tasking OS, a couple shells and the display systems to handle even displaying things like a unix-like console, a sane piping system, all the major user land utilities (sans some of the compiler things, but things like ls, cat, ps, etc.) a simple text editor and intra-system messaging system, etc. etc. etc.
It was a great curriculum and really was the first time we, as CS students, had the chance to really spend time understanding the subject matter without spending time focusing on stupid language tricks like we had in our various C and C++. The code we wrote was fairly straight forward (we were learning the language as we went, so kept to the KISS method) and focused instead of the material. It was probably among the hardest, and best class I've ever had on any subject.
Did I know Java at the end of it?
To a point -- I knew the pidgin dialect we wrote the OS in. A few semesters later I took a fluff software engineering course and had to hack out some various java server bits and had a roughshod time of it as I ran head first into the now common overengineeringitis that plagues modern Java development. I found the syntax and most of the standard library familiar, but the idiomatic ways of writing the code, community practices, the shibboleths, nearly impenetrable without years buried in an enterprise software house.
I swore off Java and never looked back...moving on to Perl and Python for a spell (incidentally my standard "learn a new language" project is to write a simple non-lexical phrase extractor, it touches I/O, data structures, database connectivity, program flow, and if I get daring, multi-threading and a few other odds and ends and usually gives me a pretty good idea how a language works.
Now years later, taking a look at Android dev, I'm finding that writing code for the platform, even though it's Java, to be like writing code for our old OS. It's pretty simple, there's great library support, and I don't have to wrap simple method calls in hundreds of lines of framework boilerplate nonsense. It's actually pretty fun.
But I've definitely been drawing heavily on that pidgin dialect of Java that I learned way back when -- it's kinda like riding a bicycle, except a few bits have changed here and there. So yeah, I think I did "learn" the language, and it's been amazing how much of it I can recall since it's been a decade since I did any coding in it.
(this method also handily solves the "I need a project, a goal, to learn the language, otherwise I'm just twiddling bits" problem).
I googled it but it leads back to this page.
- Take a lexicon (list) of single words in a given language (English for example).
- Take a block of text and think of it as an ordered sequence of tokens, news articles work really well for this approach, books not as much.
Example (from http://www.cnn.com/2012/11/02/showbiz/movies/flight-review-c...): With its spectacular plane crash -- I would rate it fractionally behind the air disasters director Robert Zemeckis staged in "Cast Away" and Joe Carnahan in "The Grey," but still more than gut-wrenching enough to make you think about taking the train, next time -- "Flight" immediately raises the stakes on your typical addiction drama. But that's essentially what it is -- with a courtroom finish for extra lift.
- Stream through the text, any word that is in your lexicon, throw away.
---- ---- ----------- ----- ----- -- - ----- ---- -- ------------ ------ --- --- --------- ------- Robert Zemeckis ------ -- "---- ----" --- Joe Carnahan -- "--- ----," --- ----- ---- ---- ------------- ------ -- ---- --- ----- ---- ----- --- -----, ---- ---- -- "------" ----------- ------ --- ------ -- ---- ------- --------- -----. --- ----'- ----------- ---- -- -- -- ---- - --------- ------ --- ----- ----.
- treat each group of remaining tokens as separate objects, in this case we have 2
- write these non-lexical (not in your original lexicon) sequences out:
Robert Zemeckis
Joe Carnahan
Boom, you just made an entity extractor that plucks names out of text without having to model the English Language too rigorously. And it generally works in most languages that have a low intersection between name-part tokens and lexicon tokens. And it can be brutally fast.
Where this gets interesting is in suppressing junk and tweaking the algorithm around things like parenthesis, apostrophese, and sentence boundaries. There's lots of little edge cases like this that you have to be mindful of - numbers in the text for example are never parts of names but aren't in your lexicon so you have to figure out what to do with those. And then you can use other heuristics to improve the results, suppose another sentence just had "Zemeckis" in it, that's a name, but then suppose another sentence had a token not in your lexicon like "Samoflange"...do you count that as a name? What about lexical tokens that are names like "Bush"? So you can try things like only counting sequences of tokens that have more than 2 tokens (like "Robert Zemeckis") and ignoring ones that have only 1.
And it goes on and on -- endless tweaks to improve the quality of the names you get and suppress non-name sequences.
To make the project more interesting, try storing your lexicon in a database or some kind of index so you can search it quickly, I like to use SQLite files with indexes on the lexicon table myself, but it's a fun assignment to try different things like in-memory TRIEs.
If you want to try threading, you can try playing around with searching the text at different start and end points (thread 1 searches the first 25% of the text, thread 2 the second 25%, etc.) or have different threads search different articles.
You can try all kinds of different things to keep it interesting and as you start abstracting the problem you can play with all kinds of different control and data structures to accomplish the task. Trying to make this as fast as possible (with all the heuristics turned on) can also be a fun challenge.
> I googled it but it leads back to this page.
It blows my mind how often this happens to me, even though I understand how and why. Especially since it's usually just a few minutes after the original comment is written. Google is awesome.
</META>
I'll also be writing some other utilities! :)
Share the code with me if you feel like it. My GitHub is https://github.com/rodrigoalvesvieira and my email is rodrigovieira1994 [at] gmail [dot] com
But if you use it to start something new, or to add to your repretoire of utilities, then that is something you're more motivated to complete and more useful expenditure of time to boot.