damn tweaks9
[lambda.git] / family_tree_of_functional_programming_languages.mdwn
1 There's a lot more trivia and links here than anyone needs to know for this seminar. It's
2 there for anyone who may be interested.
3
4 Others (and ourselves) will often talk about "functional programming
5 languages." But it would be more appropriate to talk of functional *paradigms*
6 or *programming patterns*. Most programming languages are hybrids that allow
7 programmers to use any of several programming paradigms. The ones that get
8 called "functional languages" are just ones that give functional paradigms a
9 central place in their design, and make them very easy to use.
10
11 We can divide functional languages into two classes: those that are dynamically
12 typed and those that are statically typed.
13
14 The **dynamically typed** languages give types more of a background role in the
15 program. They include the Lisp family (which in turn includes all the variants
16 of [[!wikipedia Scheme (programming language) desc="Scheme"]], and also [[!wikipedia Common Lisp]], and [[!wikipedia
17 Clojure]]). They also include [[!wikipedia Erlang (programming language) desc="Erlang"]] and [[!wikipedia Joy (programming language) desc="Joy"]] and
18 [[!wikipedia Pure (programming language) desc="Pure"]], and others.
19
20 Although these languages are hospitable to functional programming, some of them
21 also permit you to write *imperatival* code (that is, code with *side-effects*)
22 too. In Scheme, by convention, imperatival functions are named ending with a
23 "!". So `(set-car! p 1)` is a Scheme expression that, when evaluated, *mutates*
24 the pair p so that its first member changes to 1. For our purposes though,
25 we'll mostly be working with the parts of Scheme that are purely functional.
26 We'll be discussing the difference between functional and imperatival
27 programming a lot during the seminar.
28
29 We're using Scheme in parallel with our discussion of *untyped* lambda calculi.
30 Scheme isn't really untyped. If you assign a string to variable x and then try
31 to add x to 1, Scheme will realize that strings aren't the right type of value
32 to add to integers, and will complain about it. However, Scheme will complain
33 about it *at runtime*: that is, at the point when that particular instruction
34 is about the be executed. This is what's meant by calling these languages
35 "dynamically typed."
36
37 In practice, dynamically typed languages allow the programmer to be more
38 relaxed about the types of the values they're manipulating. For instance, it's
39 trivial to create a list whose first member is a string, whose second member is
40 an integer, and so on. You just have to keep track somehow so that you don't
41 try doing anything with values of the wrong type, else you'll get an error at
42 runtime.
43
44
45 The other large class of languages are **statically typed**. This means that
46 typing information is checked at *compile time*: that is, when you're
47 converting your source code into a file that your computer knows how to
48 directly execute. If you make type mistakes---for instance, you try to add a
49 string to an integer---the compiler will choke on this so you never get to the
50 point of even trying to run the program. Once you finally do get the program to
51 compile, you can be more confident that errors of that sort have all been
52 eliminated. They can't sneak up to bite you unawares while the program is
53 running.
54
55 Formerly, static typing required the programmer to add lots of annotations in
56 her source code explicitly specifying what the type of each function argument
57 is, what the type of the function's return value was, and so on. This is
58 tedious, and partly for this reason dynamically typed languages have become
59 popular and are thought of as easier to work with. However, nowadays statically
60 typed languages tend to use "type inference": that is, you can let the computer
61 do most of the work of figuring out what the types of everything are. For
62 example, if you define a function like this:
63
64         let foo x y = (1 + x, sqrt(y) )
65
66 the compiler will see that its first argument x is added to an integer, so it
67 also needs to be an integer; and (supposing sqrt is known independently to take
68 floating point arguments), foo's second argument y needs to be a floating point
69 value. What's more, foo returns a pair whose first member is of type int and
70 second member is of type float. The compiler can figure this out all on its
71 own. The programmer doesn't have to explicitly spell it out, though she could,
72 like follows:
73
74         let foo (x:int) (y:float) : int*float = (1 + x, sqrt(y) )
75
76 This just says explicitly that foo takes an argument x of type int, an argument
77 y of type float, and returns a pair of type int\*float (that is, a pair whose
78 first member is of type int and whose second member is of type float).
79
80 Type inference allows programmers to enjoy the benefits of strict compile-time
81 type-checking, which as we said, helps eliminate a large class of errors at a
82 more convenient time---when the program is being developed, rather than after
83 it's been deployed and is running. While making life easier for the programmer,
84 so that they don't have to explicitly write out the types of everything.
85 (However, if a programmer doesn't keep track of types at least in her head,
86 she's going to get into trouble and will face compile-time errors until she
87 gets everything sorted out.)
88
89 Though as we said dynamically-typed languages have become popular, programmers
90 who get used to modern statically-typed languages find them productive.
91 Sometimes they become zealots for working this way instead; in any case, they
92 say that the popular dim opinion of static typing is based on out-of-date
93 experiences of older languages like C and Java.
94
95 Most functional programming languages these days are statically typed.
96
97 We can further divide these languages based on whether they use lazy or
98 strict/eager evaluation. We'll discuss the difference between these during
99 the seminar.
100
101 Most programming languages, functional or not, use **strict/eager evaluation**. For
102 instance, languages of the ML family are all statically-typed functional
103 languages with strict/eager evaluation. These include [[!wikipedia Standard ML desc="SML"]] and
104 [[!wikipedia Caml]] and [[!wikipedia Nemerle]]. SML in turn has several variants
105 or implementations: [[!wikipedia MLton]], [[!wikipedia Standard ML of New Jersey desc="SML/NJ"]], [[!wikipedia Moscow ML]],
106 and [[!wikipedia Mythryl]]. Microsoft's [[!wikipedia F Sharp (programming language) desc="F#"]]
107 is derived from Caml.
108
109 Other statically-typed functional languages with strict/eager evaluation are
110 [[!wikipedia Scala (programming language) desc="Scala"]] and [[!wikipedia
111 Coq]]. Like Scheme, many of these languages permit *imperatival* as well as
112 functional coding; but they are regarded as functional programming languages
113 because they are so hospitable to functional programming, and give it a central
114 place in their design.
115
116 A few languages such as [[!wikipedia Miranda (programming language) desc="Miranda"]] and [[!wikipedia Haskell (programming language) desc="Haskell"]] are
117 statically-typed languages that instead mostly use **lazy evaluation**. However,
118 it'd be more strictly accurate to say Haskell is lazy *by default*. You can
119 also make Haskell evaluate some expressions strictly/eagerly; you just have to
120 ask for that explicitly. (I don't know about Miranda.) Languages like OCaml
121 are the reverse: they're strict/eager by default, but you can get lazy
122 evaluation where it's needed, you just have to ask for it explicitly.
123
124 Unlike OCaml, Haskell is much more extreme about being non-imperatival. Though
125 it's possible to write imperative code in Haskell, too; one just has to
126 encapsulate it in an "ST" or "IO" *monad*. We'll be discussing in the seminar how
127 monads can be used to create purely functional representations of imperatival
128 algorithms. (You can do the same in languages like Scheme and OCaml, too.
129 What's different is that in Haskell monads are the *only* way to deal with
130 imperatival code.)
131
132 We'll talk much more about monads, lazy vs strict evaluation, and functional vs
133 imperatival code as we proceed.
134
135 We won't much discuss static vs dynamic typing; this has to do with lower-level
136 implementation details than we'll be concerned with. However, you'll encounter
137 the difference in practice as you work with Scheme and OCaml, respectively; and
138 you'll see it referred to as you read around. So it's good for you to
139 have placed it in your mental map.
140