in reply to Re^10: World's shortest intro to function programming
in thread Thread on Joel on software forum : "I hate Perl programmers."
Yeah! I get all that no problem, but that is as useful in understanding how to program in FP as HelloWorld.(c|pl|etc.) is in teaching you how to program in an imperative language--basically nil.
FP is far more than the use of high order functions and functional composition and recursion, which can be crudely approximated by:
P:\test>p1 perl> sub prompt { printf "What's your name?: "; } sub getAnswer{ chomp( $_ =<STDIN> ); return $_; } sub greetings{ print "Hello $_[ 0 ]. Welcome to functional programming +!\n" } sub main { prompt , greetings getAnswer };; perl> main;; What's your name?: BrowserUk Hello BrowserUk. Welcome to functional programming!
The real essence and subtlety of FP is the typing system, but there is a dearth of documentation on this that isn't couched in complex theoretical explainations and references to research papers that you need a subscription to download, in pdf form (which I hate vehmently because the Adobe reader and GhostSscript UI's are so crap). And when you do download them, you need a greater-than-grad-level-degree of understanding of math notation to even begin to understand. I didn't do math at that level.
Example:
4.4.3.1 Function bindings A function binding binds a variable to a function value. The general f +orm of a function binding for variable x is: x p11 ... p1k match1 ... x pn1 ... pnk matchn where each pij is a pattern, and where each matchi is of the general f +orm: = ei where { declsi } or | gi1 = ei1 ... | gimi = eimi where { declsi } and where n>=1, 1<=i<=n, mi>=1. The former is treated as shorthand for + a particular case of the latter, namely: | True = ei where { declsi } Note that all clauses defining a function must be contiguous, and the +number of patterns in each clause must be the same. The set of patter +ns corresponding to each match must be linear---no variable is allowe +d to appear more than once in the entire set. Alternative syntax is provided for binding functional values to infix +operators. For example, these three function definitions are all equi +valent: plus x y z = x+y+z x `plus` y = \ z -> x+y+z (x `plus` y) z = x+y+z Translation: The general binding form for functions is semantically equivalent to t +he equation (i.e. simple pattern binding): x = \ x1 ... xk -> case (x1, ..., xk) of (p11, ..., p1k) match1 ... (pn1, ..., pnk) matchn where the xi are new identifiers.
And didn't that translation at the bottom really clarify everything!
Even the gentlest of the tutorials splits it time between
A picture (demo) is worth a thousand words (and 1000 trivial examples). My biggest single problem with all the "tutorial" material for FP languages, (and I think that I have read/scanned/attempted to follow all the commonly available ones for Haskell, Ocaml and Oz over the last few months), is the total absence of a fully worked, practical example. Something that starts with a real world practical problem, including all the "messy stuff" like IO, retained state (even better if a little FFI and concurrency was thrown in), and then takes you through the development process step-by-step without all the propaganda.
What I mean by "2D syntax" the Python-style required whitespace--2d alignment rules. The FP guys appear to think this is elegant, and I guess it is compared to Lispish, but the always-moving-right, "hanging indents" formatting, looks anything but elegant or even structured to my eyes.
Examples:
Lisp
defun generate-tree (phrase) "Generate a random sentence or phrase, with a complete parse tree." (cond ((listp phrase) (mapcar #'generate-tree phrase)) ((rewrites phrase) (cons phrase (generate-tree (random-elt (rewrites phrase))))) (t (list phrase))))
Haskell:
take m ys = case (m,ys) of (0,_) -> [] (_,[]) -> [] (n,x:xs) -> x : take (n-1) xs
Ocaml:
#let rec member x btree = match btree with Empty -> false | Node(y, left, right) -> if x = y then true else if x < y then member x left else member x right;; val member : 'a -> 'a btree -> bool = <fun> #let rec insert x btree = match btree with Empty -> Node(x, Empty, Empty) | Node(y, left, right) -> if x <= y then Node(y, insert x left, right) else Node(y, left, insert x right);; val insert : 'a -> 'a btree -> 'a btree = <fun>
And what is 'a? Where did that come from? "a" seems to be a "generic type placeholder" generated by the type inferencing, but what is the ' doing? Is it a function that tests the value of the type represented by the "a"?
I (vaguely) recall that in math, ' is often used to indicate the derivitive of a term or expression, but in that case it is usually used postfix, not prefix as here.
This sort of stuff pops up early and ubiquitously throughout the tutorials without any explaination. I think I tracked it down that ' is just-another-character used to create identifiers, like "_" in perl or C, but why is it used/generated here?
The Haskell tuts never explain what '$' does that I have found, but if you look at any non-trivial Haskell code, it pops up all over the place. (I know what it does now through trial and error!).
And '.'. This is explained, usually as f . g x = f( g( x )) or f . g x = (f (g x ) ) depending upon flavour, but what that doesn't tell you is when you need to use it! In most dialecs, simple abutment of functions f g x achieves the same thing--except when it doesn't and the '.' is required!
Enough ranting, (sorry you caught me after another fruitless search for information and examples, and several long and ultimately useless downloads of PDFs that I had to search manually because the stupid UI won't let me search for stuff that wasn't bloody indexed. Grrr!).
For now, I'm making best progress with Oz which has a more traditional syntax and some very nice concurrency features--despite it coming with a emacs interace (Nice OS, shame about the editor!).
I think Ocaml will (eventually) be my favorite, despite all the same charges applying, because of it's balance of FP, imperative and OO features and very efficient standalone programs. Just a shame about the aweful windows runloop interface.
I'd like to like Haskell with it's purity and laziness and monads and generics and FFI, but doing anything useful in it seems to be much harder to start with.
|
|---|