I'm looking for a useful language that is turing complete. Being predominantly a C++ programmer, I'd like a language that forces me to learn from scratch to wrap my head around it. What I hope to get out of this are new ways of approaching a programming problem and thinking it through - ways that I would not have necessarily used if I was only using C++. Any suggestions?
views:
1478answers:
20I strongly recommend haskell. No side effects when calling functions, purely functional programming experience and a helpful community (irc channel #haskell on irc.freenode.org
). You will need to rethink a lot of things you learned in C++.
i can't quantify which is 180 degrees different, but i'd suggest:
functional paradigms: common lisp, scheme, haskell
less-pure functional: ocaml, erlang, F#, scala, clojure
stack-based: forth, factor
i like this language taxonomy
http://mvanier.livejournal.com/998.html
and some really obscure ones: nemerle?
http://ola-bini.blogspot.com/2008/01/language-explorations.html
Not that different, but stack-oriented: Postscript!
And you should have a Postscript engine (AKA printer) sitting somewhere near you.
Well, there is Verilog.
Nevertheless, I think you should learn LISP. Look up "Structure and Interpretation of Computer Programs" ... actually, watch these videos:
http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/
By having a working knowledge of LISP and going through a classic such as SICP, you will be a better programmer for it.
The ones from university that I remember being the most different from anything I was used to were lisp and prolog.
I'll throw in Prolog. You'll twist your brain into knots trying to do procedural-style tasks. On the other hand, the things that Prolog are good at are very difficult to do in any procedural or OO language.
I'm not sure, however, that learning Prolog will be very helpful to other languages. The concepts you'll pick up learning a functional language like ML, Scheme, or Haskell will be applicable just about anywhere else.
BrainF*** (yes, it's a real language), this is what the "Hello world" program looks like:
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
It's Turing complete, and as far away from anything else as possibly imaginable.
If you're looking for something practical, you may want to go with a functional language (Scheme) or a more dynamic environment (Python.)
On the other hand, if you're out for pure enrichment, http://en.wikipedia.org/wiki/Category:Esoteric_programming_languages has a great list of some mind-benders. Brain will make you long for the syntactic sugar of Assembly and Befunge is not only a unique language, it's a new paradigm.
Unlambda is a good choice for SKI calculus, as are Iota and Jot, which only have two symbols a piece. If you allow for ambiguous encodings, Iota can even be written with only one symbol!
In short, what to pick is determinate on whether you're more interested in stretching or in building practical skills. Either way, have fun.
Haskell: Good pure functional language.
Lisp: http://xkcd.com/297/
Python: A scripting language, and a refreshing perspective
Ruby: I can't stand this language's style, but it's definitely different ;)
PHP: Super-easy to write code, just as easy to write crappy code. But, web programming can be educational, if you haven't done any.
EDIT: Prolog is a great one to learn, too! Logic languages are a whole other paradigm. I remember building a mini adventure game in Prolog... so, anything's possible, right?
I second Lisp. A very nice primer for that is Practical Common Lisp. Be sure to look at On Lisp, Successful Lisp, and The Common Lisp Cookbook (all freely available), too. Bookmarks for CLiki and the Hyperspec are always helpful.
For practical programming, try LISP, Haskell, or Erlang.
For something Completely Different, try SNOBOL.
Just for fun, here's a SNOBOL example program:
* WORDSIZE.SNO
*
* Program to read a file and display the number of words of
* various word lengths. To make the program more interesting,
* we shall only consider word lengths between 3 and 9. This allows
* us to demonstrate the use of an array with subscripts offset from
* 1, as well as array failure.
*
* The file being scanned is read from standard input. For example,
* to scan the file TEXT.IN, type:
*
* SNOBOL4 WORDSIZE <TEXT.IN
*
* Trim trailing blanks from input
*
&TRIM = 1
* Define pattern for words. A word consists of upper- and lower-case
* letters, apostrosphe and hyphen.
*
WORDPAT = BREAK(&LCASE &UCASE) SPAN(&LCASE &UCASE "'-") . WORD
* Define the array to hold the word counts. Valid subscripts must be
* in the range 3 through 9; all others will cause the array reference
* to fail. Array elements are initialized to zero instead of the normal
* default, which is the null string. This causes a zero to be produced
* in the printed output if a particular array entry is never incremented.
*
COUNT = ARRAY('3:9',0)
* Read a line from the input file. Fail if end-of-file.
*
READ LINE = INPUT :F(DONE)
* Find the next word in LINE, and remove it to WORD. Fail when
* no more words remain in the line.
*
NEXTW LINE WORDPAT = :F(READ)
* Increment the appropriate array element for words of this
* size. The statement quietly fails if the size is outside
* the range 3 through 9.
*
COUNT<SIZE(WORD)> = COUNT<SIZE(WORD)>+ 1 :(NEXTW)
* Upon end of file, print the values in the array. Print heading first.
*
DONE OUTPUT = "WORD LENGTH NUMBER OF OCCURRENCES"
I = 2
* Index through array starting at element 3. When we reach element
* 10, the array reference fails, and we fall through to END.
*
PRINT I = I + 1
OUTPUT = LPAD(I,5) LPAD(COUNT<I>,20) :S(PRINT)
END
I second Erlang. Listen to this interview with the creator of Erlang:
http://www.se-radio.net/podcast/2008-03/episode-89-joe-armstrong-erlang
This has many interesting implications for concurrent programming. Also, if you didn't know about se-radio, then now you do. :)
Tcl/Tk
Go for TCL, it has a perpendicular way of doing things. with no assignment operator, this will definitely be a tangential headstart.
INTERCAL. The wise designers of this legendary language realised that GOTO was harmful, so they replaced it with COMEFROM.
This introduced a minor difficulty in that it makes the program non-deterministic (when execution reaches a label, it has multiple COMEFROM statements it could jump to), but the solution turned out to be simple, elegant and powerful: just launch multiple threads and jump to all those locations at once.
Edit: actually now I think about it, it isn't that different from C++.
SMALLTALK? It is definitely a programing language much different from C++, from syntax to philosophy behind. Not to mention that in smalltalk you need to program Object Oriented, there is no escape.
There are many easily accessible languages out there that can get your brain to stretch away from C/C++ family languages. Sticking to the ones that have been around a while which I am personally familiar with:
Smalltalk is fun and gives you a view of how OO programing came to be, even if Smalltalk's object model isn't how the "popular" languages do it any more. It's rigorously OO to the point that even conditional expressions are messages passed to Boolean objects with code blocks to execute for the true and false cases. (That works better than you'd think, BTW.)
Lisp (or IMHO even better, Scheme) will stretch your brain in these directions:
- No concern for memory management
- Not much syntax - everything is a list, including programs and data. Programs can easily make other programs on the fly.
- Variables that have Values not Types
- Recursion is the most natural way to express many operations
- Lists and lists of lists, etc. as a way to express data (this will serve you well in other functional-style languages, btw)
SML is a good introduction to Functional Programming, and IMHO has foreshadowed many of the most recent developments in C# and C++:
- VERY strongly typed, though it infers types in source code so you rarely have to actually write down the types of things. The new C++ "auto" behavior was likely inspired by this feature.
- Variables that cannot be assigned to. (Also not as big a problem as you think it will be, once you learn the right way to code SML)
- Higher-order functions (the basis of C#'s delegate mechanism)
- Very concise syntax
- Strictly evaluated, which means programs actually do what you ask when you ask them to
- Uses lists as well as Lisp does, but adds a very easy mechanism akin to C structures.
- A friend once said of SML, "if you can get your code to compile, it will almost certainly run correctly the first time".
- Stroustroup likes it so it can't be all bad. :)
You can do the higher order function things with Lisp as well (Lisp originated the concept with its "lambda" expressions), but for learning I've found that SML's implementation of the concept is easier to grasp.
Haskell is a more hard-core Functional language than SML, but this gives it extra powers, too. Lazy evaluation and its implications will turn your brain and your programs inside out. Strict languages can be made to represent lazy evaluation with common idioms, but Haskell forces you to represent ordered computations by creating a cascading chain of continuations. Fortunately, that's no where near as hard to do as it sounds thanks to the concept of Monads.
By way of example, if you want to find the smallest element of a list, the most efficient way to do it in Haskell might be to take the first element of a sorted version of that list. Assuming you're using a lazy-sensible sorting algorithm (like merge sort) and don't capture the sorted list, the computer will essentially stop sorting once it finds the smallest element, and just return that.
PROLOG is another language that will stretch your mind:
- "Programs" consist of facts and rules, which correspond loosely to data and code. You "run" a Prolog program by asking the system a question.
- Rules, which are superficially like functions, do not only "run" forward, and can do some odd things.
- The best example is the "member" rule, that can both tell if an item is a member of a list AND generate all members of the list as "outputs" depending on how you use it.
And lastly, my favorite "other" language, FORTH:
- It's been described as "an assembly language like BASIC" (not a fair comparison IMHO - FORTH is way cooler than BASIC)
- It's also been described as a religion
- FORTH is what an HP RPN calculator wants to be when it grows up.
- Using FORTH as it was originally designed (as a command-line interface OS) will make you reconsider what a computer is and how it can be used. It's definitely an "old school" approach that fits better with the 8-bit TTY world than the modern GUI world, though there are modern FORTHs that can do nicely in the GUI world.
- You program a FORTH system by extending the built-in word list to add the features you need to solve your problem. At a high level, it's like using the Unix shell - you put together a set of smaller utilities to get the effect you want.