diff options
author | michele.simionato <devnull@localhost> | 2008-10-28 05:08:08 +0000 |
---|---|---|
committer | michele.simionato <devnull@localhost> | 2008-10-28 05:08:08 +0000 |
commit | 79ac60621ea0e56aaf131ca8695beff297708d48 (patch) | |
tree | 887fe2c33753deb1ce284a734df9dad80743b3c8 /ml | |
parent | 37df30254dbdbabb89a38cb8e067d479415f188d (diff) | |
download | micheles-79ac60621ea0e56aaf131ca8695beff297708d48.tar.gz |
Various fixes and improvements
Diffstat (limited to 'ml')
-rw-r--r-- | ml/intro.txt | 132 |
1 files changed, 70 insertions, 62 deletions
diff --git a/ml/intro.txt b/ml/intro.txt index 49388b0..bda328b 100644 --- a/ml/intro.txt +++ b/ml/intro.txt @@ -5,11 +5,12 @@ Functional Programming For Dynamic Programmers - Introduction :date: December 2007 This is the first of a series of articles on functional programming in -statically typed languages. It is intended for dynamic programmers, i.e. -for programmers with a background in dynamically typed languages, such as Perl, -Python, Ruby, or languages in the Lisp family. The approch is eminently practical -and example-based; the main goal is to see if we can stole some good idea from -statically typed languages. I will mostly consider languages in the ML family, because +statically typed languages. It is intended for dynamic programmers, +i.e. for programmers with a background in dynamically typed +languages, such as Perl, Python, Ruby, or languages in the Lisp +family. The approch is eminently practical and example-based; the main +goal is to see if we can stole some good idea from statically typed +languages. I will mostly consider languages in the ML family, because they are pretty nice and much easier to understand than Haskell. Declaration of intents @@ -33,18 +34,18 @@ alternatives. ll never be loyal to a single language. The *forma mentis* of the dynamic programmer is very different from the *forma mentis* of the language evangelist: the dynamic programmer can be enhaumored of language for a while, but his love will not be -exclusive. -This premise is important in order to undestand the goals of this series -of articles. The goal is not advocating functional programming. Others -have taken this role. For instance, there is an infamous -article written by John Hughes in 1984 and titled -`Why Functional Programming Matters`_ which begins with the sentence -*This paper is an attempt to demonstrate to the “real world” that functional -programming is vitally important, and also to help functional programmers -exploit its advantages to the full by making it clear what those advantages are.* -This is *not* the goal of this series of articles. The goal is this series if -merely educational, to broaden the view of the world of my readers, -including myself (after all, I am the first of my readers ;) +exclusive. This premise is important in order to undestand the goals +of this series of articles. The goal is not advocating functional +programming. Others have taken this role. For instance, there is an +infamous article written by John Hughes in 1984 and titled `Why +Functional Programming Matters`_ which begins with the sentence *This +paper is an attempt to demonstrate to the “real world” that functional +programming is vitally important, and also to help functional +programmers exploit its advantages to the full by making it clear what +those advantages are.* This is *not* the goal of this series of +articles. The goal is this series if merely educational, to broaden +the view of the world of my readers, including myself (after all, I am +the first of my readers ;) A pragmatic programmer may rightly wonder why to study functional languages, since their relevance in enterprise programming is @@ -70,47 +71,53 @@ of mutation and side-effects. I will follow this tradition too (a dynamic programmer has no obbligation to be innovative at any cost, he may well decide to follow the traditional way). -I will just add that I don't find the arguments against mutation and side effects -terribly compelling. Certainy there are bugs due to mutation and side -effects, but in my working experience they are relatively rare. Most of the bugs I have -in my code are actually issue of business logic (I understood the specs incorrectly or the -specs where incomplete); many others are due to an incomplete or wrong knowledge of -the system I have work with; and others are due to the deadlines. -I would have the same bugs even using a functional language. -On the other hand, I have nothing against diminuishing the language-related bugs, -even if they are a minority, so, let me contrast the functional way with the imperative -way here. I will mostly use Python as an example of imperative language, -because it is a language that I know well enough, and because it is -so readable that the examples will be easy to understand even for -programmers not familiar with Python. +I will just add that I don't find the arguments against mutation and +side effects terribly compelling. Certainy there are bugs due to +mutation and side effects, but in my working experience they are +relatively rare. Most of the bugs I have in my code are actually issue +of business logic (I understood the specs incorrectly or the specs +where incomplete); many others are due to an incomplete or wrong +knowledge of the system I have work with; and others are due to the +deadlines. I would have the same bugs even using a functional +language. On the other hand, I have nothing against diminuishing the +language-related bugs, even if they are a minority, so, let me +contrast the functional way with the imperative way here. I will +mostly use Python as an example of imperative language, because it is +a language that I know well enough, and because it is so readable that +the examples will be easy to understand even for programmers not +familiar with Python. Let me begin by discussing the concept of mutation. When you write code like >>> lst = []; lst.append(1) -in Python you are mutating the list ``lst``: originally it is empty, after the ``append`` -operation it contains the number ``1``. Mutation is a potential source of bugs and -there are various workaround to make the bugs less likely. For instance, Scheme and -Ruby use the *bang convention*: the name of a function/method performing mutation ends -with an exclamation mark, so that they are more visible to the programmer. Python has -no bang, but there is the convention that mutating methods returns ``None`` and -not the mutated object. Pure functional languages such as Haskell take a radication -position and they just make everything immutable. Making everything immutable -has big advantages especially in multithreaded programming, since different threads cannot -interfere each other and you can just forget about locks. On the other hand, various -programming patterns based on mutability (for instance keeping a registry of callbacks) -becames impossible. +in Python you are mutating the list ``lst``: originally it is empty, +after the ``append`` operation it contains the number ``1``. Mutation +is a potential source of bugs and there are various workaround to make +the bugs less likely. For instance, Scheme and Ruby use the *bang +convention*: the name of a function/method performing mutation ends +with an exclamation mark, so that they are more visible to the +programmer. Python has no bang, but there is the convention that +mutating methods returns ``None`` and not the mutated object. Pure +functional languages such as Haskell take a radication position and +they just make everything immutable. Making everything immutable has +big advantages especially in multithreaded programming, since +different threads cannot interfere each other and you can just forget +about locks. On the other hand, various programming patterns based on +mutability (for instance keeping a registry of callbacks) becames +impossible. Another very common operation in imperative languages is rebinding a variable. When you write code like >>> i = 1; i = i+1 -in Python, you are explicitely rebinding the name ``i`` which originally -points to the value ``1``, making it to point to the value ``2``. -This looks like an harmless operation. It is however not so harmless and it may be -the source of subtle bugs. Consider for instance the following example +in Python, you are explicitely rebinding the name ``i`` which +originally points to the value ``1``, making it to point to the value +``2``. This looks like an harmless operation. It is however not so +harmless and it may be the source of subtle bugs. Consider for +instance the following example >>> f1, f2, f3 = [lambda : i for i in (1, 2, 3)] @@ -129,8 +136,8 @@ In Haskell, where there is no rebinding, the corresponding list comprehension would return three thunks, the first one returning ``1``, the second ``2``, the third ``3`` [#]_. -.. [#] To get the same in Python you can recur to the default argument hack, i.e. you can - rewrite ``f1, f2, f3 = [lambda i=i: i for i in (1, 2, 3)]``. +.. [#] To get the same in Python you can recur to the default argument hack, + i.e. you can rewrite ``f1, f2, f3 = [lambda i=i: i for i in (1, 2, 3)]``. Finally, let me discuss the side effects issue. To be concrete, consider the following function with side effects:: @@ -140,9 +147,10 @@ the following function with side effects:: result = x * x return result -Each time the function ``square`` is called, you get a log message as side effect. -Unfortunaly, side effects do not play well with memoization techniques and if you cache -the result of ``square`` with a suitable decorator:: +Each time the function ``square`` is called, you get a log message as +side effect. Unfortunaly, side effects do not play well with +memoization techniques and if you cache the result of ``square`` with +a suitable decorator:: square = memoize(square) @@ -195,17 +203,17 @@ and better known. Programmers used to dynamic typing (i.e Pythonistas, Rubystas, etc) will have less trouble to understand dynamically typed functional language than statically types ones. -Still I think it is interesting to look at statically typed languages. After all, I think -a programmer should have at least a statically typed language in his -toolbox (C++ and Java do not count ;) Also, I should notice that there are -often issues of terminology when talking about types. Most people coming -from the dynamic world will say that their language -is strongly typed, contrasting it with weakly typed languages such as C -or Assembly, where characters are the same as short integers, or with -Perl, where 2+"3" is a valid expression and returns 5. On the other hand, -people from the static world will say than dynamically typed languages -are untyped, since you can change the type of a variable. For instance, -the following is valid Scheme code:: +Still I think it is interesting to look at statically typed +languages. After all, I think a programmer should have at least a +statically typed language in his toolbox (C++ and Java do not count ;) +Also, I should notice that there are often issues of terminology when +talking about types. Most people coming from the dynamic world will +say that their language is strongly typed, contrasting it with weakly +typed languages such as C or Assembly, where characters are the same +as short integers, or with Perl, where 2+"3" is a valid expression and +returns 5. On the other hand, people from the static world will say +than dynamically typed languages are untyped, since you can change the +type of a variable. For instance, the following is valid Scheme code:: (define a 1) (set! a "hello") |