|
1 | 1 | # About the Idris Programming Language |
2 | 2 |
|
3 | | -Idris is a *pure*, *dependently typed*, *total* *functional* programming language. I'll quickly explain each of these adjectives in this section. |
| 3 | +Idris is a *pure*, *dependently typed*, *total* *functional* programming language. |
| 4 | + |
| 5 | +Lets break that down and explore what each of those terms means on their own. |
4 | 6 |
|
5 | 7 | ## Functional Programming |
6 | 8 |
|
7 | | -In functional programming languages, functions are first-class constructs, meaning that they can be assigned to variables, passed as arguments to other functions, and returned as results from functions. Unlike for instance in object-oriented programming languages, in functional programming, functions are the main form of abstraction. This means that whenever we find a common pattern or (almost) identical code in several parts of a project, we try to abstract over this in order to have to write the corresponding code only once. We do this by introducing one or more new functions implementing this behavior. Doing so, we often try to be as general as possible to make our functions as versatile to use as possible. |
| 9 | +In functional programming languages, functions are *first-class constructs*, meaning that they can be assigned to variables, passed as arguments to other functions, and returned as results from functions, just like any other value in the language. Unlike in, for instance, object-oriented languages, functions are the main form of abstraction in functional programming. |
| 10 | + |
| 11 | +Whenever we find a common pattern or (almost) identical code in several parts of a project, we try to implement an abstraction over it to avoid write the same code multiple times. In functional programming, we do this by introducing one or more new functions implementing the required behavior, often trying to be as general as possible to maximize the versatility and re-usability of our functions. |
8 | 12 |
|
9 | | -Functional programming languages are concerned with the evaluation of functions, unlike classical imperative languages, which are concerned with the execution of statements. |
| 13 | +Functional programming languages are concerned with the evaluation of functions, unlike imperative languages, which are concerned with the execution of statements. |
10 | 14 |
|
11 | 15 | ## Pure Functional Programming |
12 | 16 |
|
13 | | -Pure functional programming languages come with an additional important guarantee: Functions don't have side effects like writing to a file or mutating global state. They can only compute a result from their arguments possibly by invoking other pure functions, *and nothing else*. As a consequence, given the same input, they will *always* generate the same output. This property is known as [referential transparency](https://en.wikipedia.org/wiki/Referential_transparency). |
| 17 | +*Pure* functional programming languages come with an additional important guarantee: |
| 18 | + |
| 19 | +Functions don't have side effects, like writing to a file or mutating global state. They can only compute a result from their arguments possibly by invoking other pure functions, *and nothing else*. Given the same input, a pure function will *always* generate the same output, this property is known as [referential transparency](https://en.wikipedia.org/wiki/Referential_transparency). |
14 | 20 |
|
15 | 21 | Pure functions have several advantages: |
16 | 22 |
|
17 | | -- They can easily be tested by specifying (possibly randomly generated) sets of input arguments together with the expected results. |
| 23 | +- They are easy to test by specifying (possibly randomly generated) sets of input arguments alongside the expected results. |
18 | 24 |
|
19 | | -- They are thread-safe, since they don't mutate global state, and as such can be freely used in several computations running in parallel. |
| 25 | +- They are thread-safe. Since they don't mutate global state, they be used in several computations running in parallel without interfering with each other. |
20 | 26 |
|
21 | 27 | There are, of course, also some disadvantages: |
22 | 28 |
|
23 | | -- Some algorithms are hard to implement efficiently using only pure functions. |
| 29 | +- Some algorithms are hard to implement efficiently with only pure functions. |
24 | 30 |
|
25 | | -- Writing programs that actually *do* something (have some observable effect) is a bit trickier but certainly possible. |
| 31 | +- Writing programs that actually *do* something (have some observable effect) is a bit tricky, but certainly possible. |
26 | 32 |
|
27 | 33 | ## Dependent Types |
28 | 34 |
|
29 | | -Idris is a strongly, statically typed programming language. This means that every Idris expression is given a *type* (for instance: integer, list of strings, boolean, function from integer to boolean, etc.) and types are verified at compile time to rule out certain common programming errors. |
| 35 | +Idris is a strongly, statically typed programming language. Every expression is given a *type* (for instance: integer, list of strings, boolean, function from integer to boolean, etc.), and types are verified at compile time to rule out certain common programming errors. |
30 | 36 |
|
31 | | -For instance, if a function expects an argument of type `String` (a sequence of unicode characters, such as `"Hello123"`), it is a *type error* to invoke this function with an argument of type `Integer`, and the Idris compiler will refuse to generate an executable from such an ill-typed program. |
| 37 | +For instance, if a function expects an argument of type `String` (a sequence of unicode characters, such as `"Hello123"`), it is a *type error* to invoke this function with an argument of type `Integer`, and Idris will refuse to compile such an ill-typed program. |
32 | 38 |
|
33 | | -Being *statically typed* means that the Idris compiler will catch type errors at *compile time*, that is, before it generates an executable program that can be run. The opposite to this are *dynamically typed* languages such as Python, which check for type errors at *runtime*, that is, when a program is being executed. It is the philosophy of statically typed languages to catch as many type errors as possible before there even is a program that can be run. |
| 39 | +Being *statically typed* means that Idris will catch type errors at *compile time*, before it generates an executable program that can be run. This stands in contrast with *dynamically typed* languages such as Python, which check for type errors at *runtime*, while a program is already being executed. It is the goal of statically typed languages to catch as many type errors as possible before there even is a program that can be run. |
34 | 40 |
|
35 | | -Even more, Idris is *dependently typed*, which is one of its most characteristic properties in the landscape of programming languages. In Idris, types are *first class*: Types can be passed as arguments to functions, and functions can return types as their results. Even more, types can *depend* on other *values*. What this means, and why this is incredibly useful, we'll explore in due time. |
| 41 | +Furthermore, Idris is *dependently typed*, which is one of its most characteristic properties in comparison to other programming languages. In Idris, types are *first class*: Types can be passed as arguments to functions, and functions can return types as their results. Types can also *depend* on other *values*, as one example, the return type of a function can depend on the value of one of its arguments. This is a quite abstract statement that may be difficult to grasp at first, but we will be exploring its meaning and the profound impact it has on programming through example as we move through this book. |
36 | 42 |
|
37 | 43 | ## Total Functions |
38 | 44 |
|
39 | | -A *total* function is a pure function, that is guaranteed to return a value of the expected return type for every possible input in a finite number of computational steps. A total function will never fail with an exception or loop infinitely, although it can still take arbitrarily long to compute its result |
| 45 | +A *total* function is a pure function which is guaranteed to return a value of its return type for every possible set of inputs in a finite number of computational steps. A total function will never fail with an exception or loop infinitely, although it can still take arbitrarily long to compute its result. |
40 | 46 |
|
41 | | -Idris comes with a totality checker built-in, which enables us to verify the functions we write to be provably total. Totality in Idris is opt-in, as in general, checking the totality of an arbitrary computer program is undecidable (see also the [halting problem](https://en.wikipedia.org/wiki/Halting_problem)). However, if we annotate a function with the `total` keyword, Idris will fail with a type error, if its totality checker cannot verify that the function in question is indeed total. |
| 47 | +Idris comes with a totality checker built-in, which allows us to verify that the functions we write are provably total. Totality in Idris is opt-in, as checking the totality of an arbitrary computer program is undecidable in the general case (a dilemma you may recognize as the [halting problem](https://en.wikipedia.org/wiki/Halting_problem)). However, if we annotate a function with the `total` keyword, and the totality checker is unable to verify that the function is, indeed, total, Idris will fail with a type error. Notably, failing to determine a function is total is not the same as judging the function to be non-total. |
42 | 48 |
|
43 | 49 | <!-- vi: filetype=idris2:syntax=markdown |
44 | 50 | --> |
0 commit comments