www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Learning Haskell makes you a better programmer?

reply Walter Bright <newshound2 digitalmars.com> writes:
I've often heard that claim, but here's an article with what the substance is:

http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=1

Note that D offers this style of programming, with checkable purity, 
immutability and ranges. I think it is a very important paradigm.
Dec 25 2012
next sibling parent reply "Jakob Bornecrantz" <wallbraker gmail.com> writes:
On Tuesday, 25 December 2012 at 19:37:42 UTC, Walter Bright wrote:
 I've often heard that claim, but here's an article with what 
 the substance is:

 http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=1

 Note that D offers this style of programming, with checkable 
 purity, immutability and ranges. I think it is a very important 
 paradigm.

I think you missed a big part here, the by default of purity. It is in D more work to enforce purity of functions then not. The other part he talked about is countered in the language (as well to a worrying degree in Phobos) with function returns of type auto. Taking his example: foo :: Map Integer String -> String -> auto Even if the function always returns integer it only requires one function to not do that and you would start second guessing every function returning auto. Cheers, Jakob.
Dec 25 2012
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/25/2012 11:57 AM, Jakob Bornecrantz wrote:
 On Tuesday, 25 December 2012 at 19:37:42 UTC, Walter Bright wrote:
 Note that D offers this style of programming, with checkable purity,
 immutability and ranges. I think it is a very important paradigm.

work to enforce purity of functions then not.

I think optional purity is pretty powerful. You can have the advantages of either, at your choice.
 The other part he talked about is countered in the language (as well to a
 worrying degree in Phobos) with function returns of type auto.

 Taking his example:
 foo :: Map Integer String -> String -> auto

 Even if the function always returns integer it only requires one function to
not
 do that and you would start second guessing every function returning auto.

Nobody makes you use auto, either.
Dec 25 2012
prev sibling next sibling parent "so" <so so.so> writes:
On Tuesday, 25 December 2012 at 19:37:42 UTC, Walter Bright wrote:
 I've often heard that claim, but here's an article with what 
 the substance is:

 http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=1

 Note that D offers this style of programming, with checkable 
 purity, immutability and ranges. I think it is a very important 
 paradigm.

Same is often said for lisp for (IMO) far far better reasons, but it is still pure nonsense. In my case, the more i learn lisp more i hate c++, and since i have to use it, i become frustrated and unproductive. C++ made me develop a hatred to the languages that get in your way for absolutely no reason (example: lack of static if) or locks you to certain paradigms (single for Haskell?). I am reading the book "Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp", and i have to say it was somewhat a shocking experience. The fact that in a popular book about the highest level language which includes chapters for writing interpreters, compilers, yet i haven't met a c/c++ book including such things, it is said these languages are one of the low level languages. I know it is much easier to write those for lisp than C, yet try to understand my point. Sorry for being a lisp advocate in D forum, but you know i am on your side, we all are (i hope) trying to find the best tool for the job.
Dec 25 2012
prev sibling next sibling parent "SomeDude" <lovelydear mailmetrash.com> writes:
On Tuesday, 25 December 2012 at 20:29:54 UTC, so wrote:
 I am reading the book "Paradigms of Artificial Intelligence 
 Programming: Case Studies in Common Lisp", and i have to say it 
 was somewhat a shocking experience. The fact that in a popular 
 book about the highest level language which includes chapters 
 for writing interpreters, compilers, yet i haven't met a c/c++ 
 book including such things, it is said these languages are one 
 of the low level languages. I know it is much easier to write 
 those for lisp than C, yet try to understand my point.

SICP also leads the student from the very basics all the way to the writing of a Scheme interpreter and a compiler in Scheme. That would probably not be possible in a reasonable number of pages for a language with a more complex syntax. Anyway, that doesn't mean that it's not possible, it's just take a whole lot more effort to do the same in C++ or in D. As for being a better programmer after having used some advanced concepts, I don't know. I think every feature of a language must be used where appropriate. I've seen some Python code using heavily map/filter/etc that was simply unreadable to me. In some places, I find it easier to understand for loops, while in other cases, using functional style programming conveys the intent better. But maybe that's just me.
Dec 25 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 25, 2012 11:37:42 Walter Bright wrote:
 I've often heard that claim, but here's an article with what the substance
 is:
 
 http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=1
 
 Note that D offers this style of programming, with checkable purity,
 immutability and ranges. I think it is a very important paradigm.

I totally agree that learning a functional language makes you a better programmer, and I think that it's awesome that we can program that way in D. However, to actually really gain the benefit in terms of learning, you probably have to actually program in a functional language, because you're _forced_ to learn how to program in a functional paradigm, whereas in D it's only an option for when you want to do so. And Haskell is a particularly good language for it, because its laziness forces it to be pretty much purely functional whereas a number of other functional languages have more back doors to imperative programming and mutation. Either way, it's great that D allows us to program in such paradigms. - Jonathan M Davis
Dec 25 2012
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 12/26/2012 12:11 AM, Walter Bright wrote:
 I think optional purity is pretty powerful. You can have the advantages of
 either, at your choice.

True, but there's a difference between what's useful when building an application, and what's useful as a learning exercise.
Dec 25 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
(In the end this answer has become a little article.)

Walter:

Being a "good programmer" means having a quite long list of 
different skills and qualities. I think that learning Haskell 
helps you improve, but only in a small percentage of those 
skills. So I think overall Haskell doesn't make a large 
difference (despite since many months I have started to study 
Haskell).

Regarding D, it's very different from Haskell, and I think it's 
very hard to learn from D what you can learn from Haskell. 
Haskell is single-paradigm and almost forces you to program in 
certain different ways.


 From that little blog post:

It forced me to think of every such problem as a chain of the 
primitive list operations, maps, folds, filters and scans. Now I 
always think in these terms. I "see" the transformation of a 
container as a simple sequence of these operations.<

Decomposing part of the code in terms of such higher order functions is sometimes a good idea that makes the code cleaner and frees the mind to think at a higher level. Python goes one step further with its list comps that make the code even more readable, removing map and filters (list comps are available in Haskell too, but the syntax is a little worse, and probably for cultural reasons it's used less than in Python): foos = (x * x for x in items if x % 2) In D you have to use map and filter to do the same thing, and it's more noisy, less readable and longer: auto foos = items.filter!(x => x % 2)().map!(x => x * x)(); In Haskell sometimes you define an inner recursive function (sometimes named "go") where in D/Python you just use a loop. The loop doesn't risk blowing the stack (especially in Python), is often equally shorter to write, and in many situations I keep finding loops more readable and cleaner than recursion. So on one hand you have C code that contains lot of hairy nested loops with twiddly pointer arithmetic, that shows you the details of how something is done, but it doesn't tell you why. To understand such C code you have to make a summary of the code in your head, and build a bit higher view of what is done (from an older version of http://rosettacode.org/wiki/Topswops ): #include <stdio.h> #include <string.h> typedef struct { char v[16]; } deck; int n, d, best[16]; void tryswaps(deck *a, int f, int s) { int i, j, k; deck b = *a; if (d > best[n]) best[n] = d; for (i = 0, k = 1 << s; k >>= 1, --s; ) { if (a->v[s] == -1 || a->v[s] == s) break; i |= k; if ((i & f) == i && d + best[s] < best[n]) return; } s++, d++; for (i = 1, k = 2; i < s; i++, k <<= 1) { if (b.v[i] == -1) { if (f & k) continue; } else if (b.v[i] != i) continue; b.v[0] = j = i; while (j--) b.v[i-j] = a->v[j]; tryswaps(&b, f|k, s); } d--; } int main(void) { deck x; memset(&x, -1, sizeof(x)); x.v[0] = 0; for (n = 1; n <= 12; n++) { best[n] = d = 0; tryswaps(&x, 1, n); printf("%2d: %d\n", n, best[n]); } return 0; } A short Haskell solution is shorter, and much cleaner/nicer if you know a little of Haskell (but also much slower, possibly ten times slower or more): import Data.List (permutations) topswops :: Int -> Int topswops n = foldl max 0 $ map topswops' $ permutations [1..n] topswops' :: [Int] -> Int topswops' xa (1:_) = 0 topswops' xa (x:_) = 1 + topswops' reordered where reordered = reverse (take x xa) ++ drop x xa main = mapM_ (\x -> putStrLn $ show x ++ ":\t" ++ show (topswops x)) [1..10] On the other hand Haskell code sometimes contains tens of tiny functions that requires you a elephant-grade long term memory (even if you are using an Haskell IDE) to remember the meaning of all those functions and several 3-4-symbol-long operators, plus it asks you a large medium-term memory to keep in mind how those numerous little functions are plugged together in complex ways to produce the results. So while I've seen both very good C and good Haskell code, in both languages it's possible to write code that requires lot of brainpower to be understood. I have found that good D code is a good middle point between those kinds of C and Haskell coding: it calls and uses a moderate amount of functions, it often uses a very limited amount of pointers, its loops usually are clean and at worst use slices instead of pointer arithmetic. And micropatterns like map and filter are available in D, but also normal loops are available to avoid recursion. Immutability is available. The end result is a kind of D code that for me avoids the problems visible in both that C and Haskell code. This is why I often use D instead of Haskell or C. (I have not yet studied Scala, maybe it offers similar qualities as D or maybe even better, despite on the JavaVM it often doesn't allow you to specify with enough precision the layout of the data structures in memory). This is a modified D version of the C code (it's not exactly equal), and for me it's significantly more clean than that C code: import std.algorithm, std.range; uint topswops(in uint n) nothrow in { assert(n > 0 && n < 32); } body { static uint[32] best; alias T = byte; alias Deck = T[best.length]; void trySwaps(in ref Deck deck, in uint f, in uint d) nothrow { if (d > best[n]) best[n] = d; foreach_reverse (i; 0 .. n) { if (deck[i] == -1 || deck[i] == i) break; if (d + best[i] <= best[n]) return; } Deck deck2 = deck; foreach (i; 1 .. n) { immutable uint k = 1U << i; if (deck2[i] == -1) { if (f & k) continue; } else if (deck2[i] != i) continue; deck2[0] = cast(T)i; foreach_reverse (j; 0 .. i) deck2[i - j] = deck[j]; // Reverse copy. trySwaps(deck2, f | k, d + 1); } } best[n] = 0; Deck deck0 = -1; deck0[0] = 0; trySwaps(deck0, 1, 0); return best[n]; } void main() { import std.stdio; foreach (i; 1 .. 12) writefln("%2d: %d", i, topswops(i)); } Using templates you can make that D code about twice faster. That D code is still low-level, it contains a static variable, but still that code is much simpler to understand compared to that C code. In that D code this is an alternative way to write the reverse copy, but unfortunately here you have to pay some abstraction penalty, because using DMD this makes the code significantly slower (in Phobos "copyTo" is named "copy" but I prefer "copyTo" to remind me what the source and destination are!): deck[0 .. i].copyTo(deck2[1 .. i + 1].retro()); That D code is quite "algorithmic" and designed for speed. If you care less for performance it's easy to write higher level D code that's shorter and easy to understand: import std.stdio, std.algorithm, std.range, permutations2; uint topswops(in uint n) in { assert (n > 0 && n < 32); } body { static uint flip(uint[] deck) pure nothrow { uint[32] temp = void; temp[0 .. deck.length] = deck[]; uint count = 0; for (auto t0 = temp[0]; t0; t0 = temp[0]) { temp[0 .. t0 + 1].reverse(); // Slow with DMD. count++; } return count; } return iota(n).array().permutations!0().map!flip().reduce!max(); } void main() { foreach (i; 1 .. 11) writefln("%2d: %d", i, topswops(i)); } There are ways to write this D code in an even a little simpler way to understand, producing a little longer (less packed) code. On the other hand D is not perfect, and there are always bad parts or things to improve in everything. The lack of a "yield" as in Python makes many D coding patterns less handy (and the lack of list comps makes the D code a little less readable, but this is less important). The lazy lists of Haskell (also present in some form in Perl6 and Scala) offer some handy coding patterns, that are rather harder to use in D. The lack of good subtyping makes D code less strong (I have discussed it some times, like here http://forum.dlang.org/thread/pxnyniryvdwpdxoymuau forum.dlang.org ). In D sometimes the creation of immutable data structures is not handy. I have discussed this in two or more past posts. If you compare Haskell with D, the use and management of the Maybe Haskell type is much better than the Nullable of Phobos, because of D lack of both pattern matching and of a bit of typestate (that should allow D to know that in the "else" branch of a not-null test of a Nullable with isNull, the type is not null, it can't throw an exception and it can be used safely). Some of such things should be improved in D language and Phobos, where possible. -------------------- SomeDude:
I've seen some Python code using heavily map/filter/etc that was 
simply unreadable to me.<

Pythonic code does not contain many map/filter (Pythonic code uses lazy or eager list comps). So probably that was bad Python code, or at least not pythonic. Bye, bearophile
Dec 25 2012
prev sibling next sibling parent "so" <so so.so> writes:
On Tuesday, 25 December 2012 at 20:50:35 UTC, SomeDude wrote:

 As for being a better programmer after having used some 
 advanced concepts, I don't know. I think every feature of a 
 language must be used where appropriate. I've seen some Python 
 code using heavily map/filter/etc that was simply unreadable to 
 me. In some places, I find  it easier to understand for loops, 
 while in other cases, using functional style programming 
 conveys the intent better. But maybe that's just me.

I didn't know "set -o vi" until a few weeks ago, learning it made me a better linux user as i knew both vi and terminal. but it didn't make me a better pc user generally. If my environment doesn't evolve with me or lack tools to combine to make something new (probably i'm repeating myself) than i gain nothing from learning a feature of another language. IMO, learning programming language X doesn't make you a better programmer. Learning X make you better X programmer. But if your existing environment/language is extremely flexible, takes code generation *very* seriously, you have a case. You gain something from learning a new feature or a paradigm. That is why lisp fascinates me, as i believe code generation is one of the most important (if not the most important) thing in a PL.
Dec 25 2012
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 12/25/2012 11:37 AM, Walter Bright wrote:

 http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=1

I think I am being a troll but that page is dark white on white! Ali
Dec 25 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Tuesday, 25 December 2012 at 20:50:35 UTC, SomeDude wrote:
 I've seen some Python code using heavily map/filter/etc that 
 was simply unreadable to me.

I've written Python code like that, which was also unreadable to me. 8-)
Dec 25 2012
prev sibling next sibling parent Iain Buclaw <ibuclaw ubuntu.com> writes:
--047d7bf0d0b2cc1fe004d1c06fbc
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On 26 December 2012 00:54, Ali =C7ehreli <acehreli yahoo.com> wrote:

 On 12/25/2012 11:37 AM, Walter Bright wrote:

 http://dubhrosa.blogspot.co.**uk/2012/12/lessons-learning-**


 I think I am being a troll but that page is dark white on white!

 Ali

--=20 Iain Buclaw *(p < e ? p++ : p) =3D (c & 0x0f) + '0'; --047d7bf0d0b2cc1fe004d1c06fbc Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On 2= 6 December 2012 00:54, Ali =C7ehreli <span dir=3D"ltr">&lt;<a href=3D"mailt= o:acehreli yahoo.com" target=3D"_blank">acehreli yahoo.com</a>&gt;</span> w= rote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;borde= r-left:1px #ccc solid;padding-left:1ex"> On 12/25/2012 11:37 AM, Walter Bright wrote:<br> <br> &gt; <a href=3D"http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-has= kell.html?m=3D1" target=3D"_blank">http://dubhrosa.blogspot.co.<u></u>uk/20= 12/12/lessons-learning-<u></u>haskell.html?m=3D1</a><br> <br> I think I am being a troll but that page is dark white on white!<span class= =3D"HOEnZb"><font color=3D"#888888"><br> <br> Ali<br> <br> </font></span></blockquote></div><br></div><div class=3D"gmail_extra">It&#3= 9;s called grey.=A0 Or gray if you speak american. :o)<br></div><div class= =3D"gmail_extra"><br clear=3D"all"><br>-- <br>Iain Buclaw<br><br>*(p &lt; e= ? p++ : p) =3D (c &amp; 0x0f) + &#39;0&#39;; </div></div> --047d7bf0d0b2cc1fe004d1c06fbc--
Dec 26 2012
prev sibling next sibling parent reply "renoX" <renozyx gmail.com> writes:
On Tuesday, 25 December 2012 at 19:37:42 UTC, Walter Bright wrote:
 I've often heard that claim, but here's an article with what 
 the substance is:

 http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=1

 Note that D offers this style of programming, with checkable 
 purity, immutability and ranges. I think it is a very important 
 paradigm.

Bleah, one good practice that I like to follow is to (optionaly) log what my functions do, so it doesn't match well with "IO change the type of your function"..
Dec 26 2012
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/26/12 9:11 AM, renoX wrote:
 On Tuesday, 25 December 2012 at 19:37:42 UTC, Walter Bright wrote:
 I've often heard that claim, but here's an article with what the
 substance is:

 http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=1

 Note that D offers this style of programming, with checkable purity,
 immutability and ranges. I think it is a very important paradigm.

Bleah, one good practice that I like to follow is to (optionaly) log what my functions do, so it doesn't match well with "IO change the type of your function"..

debug statements to the rescue! Andrei
Dec 26 2012
prev sibling next sibling parent reply Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Tue, 2012-12-25 at 11:37 -0800, Walter Bright wrote:
 I've often heard that claim, but here's an article with what the substanc=

=20
 http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=3D=

=20
 Note that D offers this style of programming, with checkable purity,=20
 immutability and ranges. I think it is a very important paradigm.

Does D do tail recursion optimisation? Can the D compiler check to enforce *NO* (or at the worst single) assignment to a variable? I am guessing that the D compilers can enforce referential transparency and zero side-effects. Functional programming is a good influence, but in it's Haskell form is liable a minority language. Clojure could make Lisp a mainstream language, but.. In the end the move to declarative expression and internal rather than external iteration is a move all languages are taking: C++, Python, D, Go, Java,.. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 26 2012
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/26/12 9:42 AM, Russel Winder wrote:
 On Tue, 2012-12-25 at 11:37 -0800, Walter Bright wrote:
 I've often heard that claim, but here's an article with what the substance is:

 http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=1

 Note that D offers this style of programming, with checkable purity,
 immutability and ranges. I think it is a very important paradigm.

Does D do tail recursion optimisation?

Yah, but not tail calls. (That should be on the list...)
 Can the D compiler check to enforce *NO* (or at the worst single)
 assignment to a variable?

Only for immutable data. Andrei
Dec 26 2012
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/26/12 11:34 AM, Russel Winder wrote:
 On Wed, 2012-12-26 at 11:03 -0500, Andrei Alexandrescu wrote:
 On 12/26/12 9:42 AM, Russel Winder wrote:

 Does D do tail recursion optimisation?

Yah, but not tail calls. (That should be on the list...)

I'll have to admit confusion from the above statement: tail calls are a programmer technique, tail call optimization is a compiler / run time technique. If a programmer uses tail calls and the compiler realizes tail call optimization then the result is equivalent to iteration.

A few rough definitions: Tail recursion: the last evaluation performed in a branch of a function is a call to itself. Tail recursion optimization: replace tail recursion with a GOTO the entry point of the function. Tail call: the last evaluation performed in a branch of a function is a call to another function. Tail call optimization: replace tail call with a GOTO the entry point of the called function.
 Can the D compiler check to enforce *NO* (or at the worst single)
 assignment to a variable?

Only for immutable data.

But isn't that the whole point, in functional programming there is only immutable data. Thus a programming language that allows mutable data cannot really be said to be usable for functional programming style.

Yah, that's the whole point so we're in good shape there.
 On the other hand it is 2012-12-26T16:32 and nearly time for fireworks,
 and drinkies. Hopefully everyone is having a peaceful and happy
 Solstice/Xmas/New Year/Hogmanay/<insert your personal choice of excuse
 for celebration>.

Same to all from yours truly! Andrei
Dec 26 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/26/2012 8:34 AM, Russel Winder wrote:
 But isn't that the whole point, in functional programming there is only
 immutable data.  Thus a programming language that allows mutable data
 cannot really be said to be usable for functional programming style.

In D, you can declare immutable data and immutable data structures. This makes it usable for FP style (along with checkable function purity). But D also does something I think is fairly unique. A function can be pure, but inside that function, mutation is allowed as long as that mutation does not "leak" outside of the function. A pure function with immutable parameters does completely specify the function in its signature. What happens inside the function is not relevant, it is not necessary that locals be immutable.
Dec 26 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12/26/2012 11:09 PM, Walter Bright wrote:
 On 12/26/2012 8:34 AM, Russel Winder wrote:
 But isn't that the whole point, in functional programming there is only
 immutable data.  Thus a programming language that allows mutable data
 cannot really be said to be usable for functional programming style.

In D, you can declare immutable data and immutable data structures. This makes it usable for FP style (along with checkable function purity).

immutable and const are incompatible with lazy evaluation. Lazy evaluation is not strictly necessary for FP, but it makes code a lot more expressive. (D ranges are lazy.)
 But D also does something I think is fairly unique. A function can be
 pure, but inside that function, mutation is allowed as long as that
 mutation does not "leak" outside of the function.  A pure function with
 immutable parameters does completely specify the function in its
 signature. What happens inside the function is not relevant, it is not
 necessary that locals be immutable.

Haskell has this.
Dec 26 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/26/12 6:13 PM, Timon Gehr wrote:
 But D also does something I think is fairly unique. A function can be
 pure, but inside that function, mutation is allowed as long as that
 mutation does not "leak" outside of the function. A pure function with
 immutable parameters does completely specify the function in its
 signature. What happens inside the function is not relevant, it is not
 necessary that locals be immutable.

Haskell has this.

This would necessitate a bit of qualification :o). Andrei
Dec 26 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12/27/2012 12:53 AM, Andrei Alexandrescu wrote:
 On 12/26/12 6:13 PM, Timon Gehr wrote:
 But D also does something I think is fairly unique. A function can be
 pure, but inside that function, mutation is allowed as long as that
 mutation does not "leak" outside of the function. A pure function with
 immutable parameters does completely specify the function in its
 signature. What happens inside the function is not relevant, it is not
 necessary that locals be immutable.

Haskell has this.

This would necessitate a bit of qualification :o). Andrei

http://www.haskell.org/haskellwiki/Monad/ST
Dec 26 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/26/12 7:11 PM, Timon Gehr wrote:
 On 12/27/2012 12:53 AM, Andrei Alexandrescu wrote:
 On 12/26/12 6:13 PM, Timon Gehr wrote:
 But D also does something I think is fairly unique. A function can be
 pure, but inside that function, mutation is allowed as long as that
 mutation does not "leak" outside of the function. A pure function with
 immutable parameters does completely specify the function in its
 signature. What happens inside the function is not relevant, it is not
 necessary that locals be immutable.

Haskell has this.

This would necessitate a bit of qualification :o). Andrei

http://www.haskell.org/haskellwiki/Monad/ST

That's not the same! Andrei
Dec 26 2012
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/26/12 8:43 PM, Timon Gehr wrote:
 It is isolated state mutation inside a pure function, which is what
 Walter emphasized on.

Point taken, but claiming it's the same thing is a bit of a stretch. Andrei
Dec 26 2012
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/28/2012 12:13 AM, Red wrote:
 Why is immutable data considered necessary for functional programming style?
 Can't a a programmer or programmer just do the same thing with mutable data,
but
 not mutate it?

People who say that C++ supports functional programming make exactly that argument. The problem, though, is this: T func(U u); // this is a pure function What does that tell you about func? It takes a U as one of its inputs, and returns an instance of T. The comment, of course, means nothing. func may read or write mutable global state, it may mutate whatever u references. How would you know? If you wrote all the code yourself, and you didn't make any mistakes, perhaps you would know. But if you are handed this code, or you work on a team, you would have no idea. There is no tool to check it, so you'd be reduced to manually going through every line of it and every line of every function that func() calls, etc. Then when a member of your team checks in code, you're back to square one, and have to start over with the manual verification, and hope you didn't make a mistake with that. Of course, nobody does something that tedious, and defaults back to trusting the comment, which is what I'd call "faith-based programming". I don't believe that faith-based programming scales well at all. Programs are getting bigger and bigger all the time, and the growth of static analysis tools suggests that we *need* mechanical verification of properties. Faith-based programming is going to wind up on the ash heap of history. The bottom line is that a language that does not support mechanical verification of functional programming, does not support functional programming.
Dec 28 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Wed, 2012-12-26 at 01:45 +0100, so wrote:
[=E2=80=A6]
 IMO, learning programming language X doesn't make you a better=20
 programmer. Learning X make you better X programmer. But if your=20
 existing environment/language is extremely flexible, takes code=20
 generation *very* seriously, you have a case. You gain something=20
 from learning a new feature or a paradigm. That is why lisp=20
 fascinates me, as i believe code generation is one of the most=20
 important (if not the most important) thing in a PL.

The experimental evidence from psychology of programming research is exactly that the more distinct computational models that a programmer is able to use reasonably well then the better programmer the person is in any specific programming language. Groovy has abstract syntax transforms, Scala has followed Lisp and introduced macros =E2=80=93 not to be confused with the C pre-processor thi= ngs of similar name. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 26 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Tue, 2012-12-25 at 21:50 +0100, SomeDude wrote:
[=E2=80=A6]
=20
 As for being a better programmer after having used some advanced=20
 concepts, I don't know. I think every feature of a language must=20
 be used where appropriate. I've seen some Python code using=20
 heavily map/filter/etc that was simply unreadable to me. In some=20
 places, I find  it easier to understand for loops, while in other=20
 cases, using functional style programming conveys the intent=20
 better. But maybe that's just me.

Code using map/filter/reduce requires a specific reading strategy, which is fine for people coming from Lisp/Clojure/Haskell/OCaml/Groovy/Ruby but difficult for people coming from C, assembly language, Java, etc. C ++ and D are treading a middle ground. BDFL has stated that list/dictionary/set comprehensions are to be preferred over functional chaining constructs. In general this is good advice, even for languages other than Python. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 26 2012
prev sibling next sibling parent "renoX" <renozyx gmail.com> writes:
On Wednesday, 26 December 2012 at 16:01:27 UTC, Andrei 
Alexandrescu wrote:
 On 12/26/12 9:11 AM, renoX wrote:
 On Tuesday, 25 December 2012 at 19:37:42 UTC, Walter Bright 
 wrote:
 I've often heard that claim, but here's an article with what 
 the
 substance is:

 http://dubhrosa.blogspot.co.uk/2012/12/lessons-learning-haskell.html?m=1

 Note that D offers this style of programming, with checkable 
 purity,
 immutability and ranges. I think it is a very important 
 paradigm.

Bleah, one good practice that I like to follow is to (optionaly) log what my functions do, so it doesn't match well with "IO change the type of your function"..

debug statements to the rescue! Andrei

Yes of course, but what I was objecting is the article's take that IO should change the type of the function: that's an oversimplification.. This is not true for debug/logging statements. renoX
Dec 26 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Wed, 2012-12-26 at 11:03 -0500, Andrei Alexandrescu wrote:
 On 12/26/12 9:42 AM, Russel Winder wrote:

 Does D do tail recursion optimisation?

Yah, but not tail calls. (That should be on the list...)

I'll have to admit confusion from the above statement: tail calls are a programmer technique, tail call optimization is a compiler / run time technique. If a programmer uses tail calls and the compiler realizes tail call optimization then the result is equivalent to iteration.
 Can the D compiler check to enforce *NO* (or at the worst single)
 assignment to a variable?

Only for immutable data.

But isn't that the whole point, in functional programming there is only immutable data. Thus a programming language that allows mutable data cannot really be said to be usable for functional programming style. On the other hand it is 2012-12-26T16:32 and nearly time for fireworks, and drinkies. Hopefully everyone is having a peaceful and happy Solstice/Xmas/New Year/Hogmanay/<insert your personal choice of excuse for celebration>. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 26 2012
prev sibling next sibling parent "Aquiles" <aquiles.a.lopez gmail.com> writes:
I will humbly offer my opinion as a guy who is learning both D 
and Haskell.

Here are some of the finer points of Haskell that has directly 
improved my programming:

Referential Transparency takes away mutation and gives you 
reliable composition. To do anything useful in Haskell you have 
to at some point compose functions. To compose functions 
effectively you have to think about what your functions 
input/output are and how they relate. So instead of having a sink 
function that returns nothing and does magic inside you think in 
terms of testable individual components that focus only on one 
aspect of the computation.

Recursion and Breaking apart tough problems. When you are forced 
to think recursively you have to think of your base cases, your 
invariants, your pre and post conditions, and how you get from 
x[k] -> x[k+1] without violating your contract. Again it 
encourages deliberate design as opposed to empirical exploration.

Type Classes are an abstraction on types similar to those found 
in D and C++. It removes the idea that interfaces are an OOP 
construct instead shows you how you can design the basis of 
communication between data by supporting a set of functions.

Lastly, I found GHC really helpful in its brutal nit-picking of 
types, inferences, etc. This helps in making the transition from 
writing code for the compiler, to writing code with the compiler.

How this has benefited my view of D:

Think about the overall system as a series of composable 
components that have predictable behaviour.
Think about the details of each component and how you can verify 
the output.
Think about the base-case and the special-case when creating a 
procedure.
Use the syntax to help the compiler understand what your intent 
is.

D helps with:

* uniform function syntax
* templates
* guards
* contracts: in, out, body
* built in unittest
* compile time assertions, conditionals, expressions

In closing, I don't think Haskell is meant to make you a better 
programmer by flexing your higher-order function manipulation or 
using FP idioms in an OOP/imperative context. It's strength, at 
least for me, has been the thought process behind functional 
programming and how to apply its view of data to your programming 
language.
Dec 26 2012
prev sibling next sibling parent "Phil Lavoie" <maidenphil hotmail.com> writes:
I have learned Haskell during my bachelor's degree and I cannot 
say it has made a big difference for me, although I do understand 
why people like the concepts of it. Recently, I was suggested by 
a professor to re-learn it. He suggested me so because I was 
making a presentation on how to extend the standard library of my 
university's pet language NIT, which is pure object oriented. 
Apparently, he thought that my additions were influenced by the 
functional paradigm.

Therefore, following his suggestion, I re-learned Haskell and 
tried to implement my master's project in it, to sort of test it 
out.

I was pleased because Haskell:
-Emphasizes more on formalism than actual machine code algorithms
-Abstract much of the machine oriented concepts in the favor of 
more mathemathical ones
-The resulting code CAN BE much, much more lightweight

I was displeased because:
-When it comes to IO, you have to work harder, and IO it is for 
real world applications
-IO and mutable states also include a whole bunch of complicated 
data structures /algorithms which are just a pain to implement in 
Haskell compared to machine oriented languages

So I just abandoned the idea (I used complicated data 
structures). I think what Bearophile said sums it up the best: 
It's really a matter of what is the problem you and how you are 
planning to solve it. Sometimes a paradigm fits best, sometimes 
its a burden. Sometimes a language is better, sometimes it isn't.

Most of the times, I find extensions of procedural languages to 
be the best answers. And this is why I love D. Power, 
flexibility, support for A LOT of paradigms with the right amount 
of compromises. Describing the language features and comparing it 
to others just don't show how great it is. D starts to shine when 
you actually program something complicated in it.

Often, when using D, I found myself thinking: "Oh! I can do that, 
sweet!", rather than: "Oh! I can't do that, right... So how to I 
workaround it...". Some people think that the "working around it" 
is the true benefit of functional languages, and there are times 
when they are right, and there are times when they aren't.

In conclusion I'd say that yeah, maybe Haskell can make you a 
better programmer, but maybe it won't change a thing. 
Incorporating many concepts and paradigms and knowing when which 
is best, that is the true challenge: not being forced to use one 
for everything. So maybe Haskell will help you understand 
functional paradigm, and that is what's great about it. But, 
IMHO, when you construct a huge software using multiple 
inputs/outputs/data structures/arcane algorithms/..., the 
functional paradigm might get in your way...
Dec 26 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Russel Winder:

 Clojure could make Lisp a mainstream language,

Many things I read in blogs and Reddit about Clojure are wrong, or nearly wrong. Bye, bearophile
Dec 26 2012
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 26 December 2012 at 18:02:42 UTC, Phil Lavoie wrote:
 Often, when using D, I found myself thinking: "Oh! I can do 
 that, sweet!", rather than: "Oh! I can't do that, right... So 
 how to I workaround it...". Some people think that the "working 
 around it" is the true benefit of functional languages, and 
 there are times when they are right, and there are times when 
 they aren't.

That is exactly my methodology to find ICE. The problem is that usually try to accomplish something in the process.
Dec 26 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Aquiles:

 When you are forced to think recursively you have to think of 
 your base cases, your invariants, your pre and post conditions, 
 and how you get from x[k] -> x[k+1] without violating your 
 contract. Again it encourages deliberate design as opposed to 
 empirical exploration.

A solution here is to think about loop pre-condition, invariant and variant, instead of throwing all loops away to replace them with recursions. Time ago I have suggested to enhance D contract programming a bit, allowing the invariant {} statement in the middle of loops. Formally this adds nearly nothing over using a nested scope {... assert(...);} but it makes more explicit to the code reader what's in that part of the code, and it guides the mind of the code writer in thinking about invariants. So in the end it seems worth a little enhancement request. Bye, bearophile
Dec 26 2012
prev sibling next sibling parent "Thiez" <thiezz gmail.com> writes:
On Wednesday, 26 December 2012 at 22:09:26 UTC, Walter Bright 
wrote:
 But D also does something I think is fairly unique. A function 
 can be pure, but inside that function, mutation is allowed as 
 long as that mutation does not "leak" outside of the function. 
 A pure function with immutable parameters does completely 
 specify the function in its signature. What happens inside the 
 function is not relevant, it is not necessary that locals be 
 immutable.

Rust can also do this. Apparently there were (are?) plans to allow pure functions that call impure delegates, as long as the delegate has been provided by the caller, but I'm not sure if they implemented that yet (or perhaps they've ditched the idea entirely).
Dec 26 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2012-11-26 00:12, Walter Bright <newshound2 digitalmars.com> wrote:

 On 12/25/2012 11:57 AM, Jakob Bornecrantz wrote:
 On Tuesday, 25 December 2012 at 19:37:42 UTC, Walter Bright wrote:
 Note that D offers this style of programming, with checkable purity,
 immutability and ranges. I think it is a very important paradigm.

D more work to enforce purity of functions then not.

I think optional purity is pretty powerful. You can have the advantages of either, at your choice.

Absolutely. But whether purity should be the default or not is orthogonal to this. I would have preferred opt-out purity to opt-in, but it's not exactly make or break. -- Simen
Dec 26 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Simen Kjaeraas:

 Absolutely. But whether purity should be the default or not is 
 orthogonal to this.

 I would have preferred opt-out purity to opt-in, but it's not 
 exactly make or break.

The colourful Erik Meijer says that specifying what functions are not pure is better than specifying what functions are pure: http://www.youtube.com/watch?v=z0N1aZ6SnBk#t=54m53s Bye, bearophile
Dec 26 2012
prev sibling next sibling parent "Timon Gehr" <timon.gehr gmx.ch> writes:
On Thursday, 27 December 2012 at 00:56:02 UTC, Andrei 
Alexandrescu wrote:
 On 12/26/12 7:11 PM, Timon Gehr wrote:
 On 12/27/2012 12:53 AM, Andrei Alexandrescu wrote:
 On 12/26/12 6:13 PM, Timon Gehr wrote:
 But D also does something I think is fairly unique. A 
 function can be
 pure, but inside that function, mutation is allowed as long 
 as that
 mutation does not "leak" outside of the function. A pure 
 function with
 immutable parameters does completely specify the function 
 in its
 signature. What happens inside the function is not 
 relevant, it is not
 necessary that locals be immutable.

Haskell has this.

This would necessitate a bit of qualification :o). Andrei

http://www.haskell.org/haskellwiki/Monad/ST

That's not the same! Andrei

It is isolated state mutation inside a pure function, which is what Walter emphasized on.
Dec 26 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, December 27, 2012 02:22:44 bearophile wrote:
 Simen Kjaeraas:
 Absolutely. But whether purity should be the default or not is
 orthogonal to this.
 
 I would have preferred opt-out purity to opt-in, but it's not
 exactly make or break.

The colourful Erik Meijer says that specifying what functions are not pure is better than specifying what functions are pure: http://www.youtube.com/watch?v=z0N1aZ6SnBk#t=54m53s

It probably would be better for stuff like safe and pure to be the default, but it's far too late for that now, regardless of how good an idea it would have been. Live and learn. - Jonathan M Davis
Dec 26 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Wed, 2012-12-26 at 22:48 +0100, bearophile wrote:
 Russel Winder:
=20
 Clojure could make Lisp a mainstream language,

Many things I read in blogs and Reddit about Clojure are wrong,=20 or nearly wrong.

Reddit appears to be full of bluster, bullshit and rubbish which is why it is entirely ignorable. =20 Practical experience, i.e. actually using it for real on real projects, indicates that Clojure is an excellent language and very usable. Moreover many people (*) building systems are actually working with Clojure and finding it a huge boon. Also Uncle Bob tells us it is the final programming language ;-) The JVM language set is definitely now Java, Scala, Groovy, Clojure. (*) OK mostly young entrepreneurial types doing start-ups. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 27 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Russel Winder:

 Practical experience, i.e. actually using it for real on real
 projects, indicates that Clojure is an excellent language and
 very usable.

In my very limited Clojure experience I've seen that it uses a LOT of memory even for my small programs, sometimes almost ten times more than equivalent Python programs (like 120 MB for a small program that processes small genomic text files). And I've seen to write fast Clojure programs I have to add a ton of annotations to the code. So I have not used it further. Bye, bearophile
Dec 27 2012
prev sibling next sibling parent "Chris" <wendlec tcd.ie> writes:
On Thursday, 27 December 2012 at 11:45:45 UTC, Russel Winder 
wrote:
 On Wed, 2012-12-26 at 22:48 +0100, bearophile wrote:
 Russel Winder:

projects, indicates that Clojure is an excellent language and very usable. Moreover many people (*) building systems are actually working with Clojure and finding it a huge boon. Also Uncle Bob tells us it is the final programming language ;-) The JVM language set is definitely now Java, Scala, Groovy, Clojure. (*) OK mostly young entrepreneurial types doing start-ups.

It all depends on who you are catering for and what you are developing. If you have to develop cross-platform applications with (possibly) graphical user interfaces any Java based technology (ironically enough!) can quickly turn into a nightmare. There's always at least one serious pitfall and I have learned that you cannot pass the burden of dealing with things like JVMs on to the user. Also, over the years I have taken a dislike to "ideological" languages that dictate a certain paradigm or coding style (Python). What attracted me to D was the lack of "ideology" (multi-paradigm) and its natively-compiled cross-platform approach with easy C/C++-integration. Before I discovered D I was at a loss trying to find a modern language (= concise and productive) that would work natively on different platforms, because I am working in a small team and "write once run everywhere" is really important. All other features like pure and safe programming, unit tests, contract programming etc. are nice and helpful (_optional_) features but were not a top priority. From my point of view the only really important issue is concurrency programming, multithreading and everything related to it. One of the biggest strengths of D is the philosophy "Well, you needn't...but you can of course"
Dec 27 2012
prev sibling next sibling parent "Red" <resmith lavabit.com> writes:
Why is immutable data considered necessary for functional 
programming style? Can't a a programmer or programmer just do the 
same thing with mutable data, but not mutate it? That is, 
couldn't Python be used for functional programming?
Dec 28 2012
prev sibling next sibling parent "evilrat" <evilrat666 gmail.com> writes:
On Friday, 28 December 2012 at 08:13:05 UTC, Red wrote:
 Why is immutable data considered necessary for functional 
 programming style? Can't a a programmer or programmer just do 
 the same thing with mutable data, but not mutate it? That is, 
 couldn't Python be used for functional programming?

well one of the points of immutable data is safely sharing across threads(the point there is that data once allocated doesn't changes so no need to sync it), functional languages also claims that they provides easy concurrency(if not "automagically"), but i can't say how it's really "easy" since i mostly do imperative and object programming.
Dec 28 2012
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 28 December 2012 at 08:13:05 UTC, Red wrote:
 Why is immutable data considered necessary for functional 
 programming style? Can't a a programmer or programmer just do 
 the same thing with mutable data, but not mutate it? That is, 
 couldn't Python be used for functional programming?

It depends what you mean by functional. It seems to me that you'll find 2 major things that are usually understood as functionnal : - abstraction based on first class function. javascript is the perfect example here, and is functional. - purity and immutability. If you have no tools to enforce immutability, you need to completely break abstraction to get the benefit. This is bug prone and will not scale (without abstraction nothing big is achievable).
Dec 28 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Fri, 2012-12-28 at 09:13 +0100, Red wrote:
 Why is immutable data considered necessary for functional=20
 programming style? Can't a a programmer or programmer just do the=20
 same thing with mutable data, but not mutate it? That is,=20
 couldn't Python be used for functional programming?

Because immutable state is a concept entirely missing from functional languages: functional languages have no tools for handling mutable state. OK Haskell has introduced arrays and indexing but it remains a dark corner for most use cases. Yes, but=E2=80=A6 if a language provide features you would be writing in a non-idiomatic way to simply ignore those features. The issue here is that a language will embody a computational model and an idiomatic mode of expression of algorithms. A language should always be used in as idiomatic way as possible. To use an imperative language in a purely functional way will lead to poor code. Conversely all use of mutable shared state is a code smell that should lead to a refactoring. Python cannot be used for functional programming in the purist sense due to lack of single assignment, presence of for and while loops, and lack of tail recursion optimization. However with higher order functional, list, set and dictionary comprehensions, many of the techniques and idioms of functional programming can, indeed should, be used when programming in Python. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 28 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Thu, 2012-12-27 at 12:59 +0100, bearophile wrote:
[=E2=80=A6]
 In my very limited Clojure experience I've seen that it uses a=20
 LOT of memory even for my small programs, sometimes almost ten=20
 times more than equivalent Python programs (like 120 MB for a=20
 small program that processes small genomic text files). And I've=20
 seen to write fast Clojure programs I have to add a ton of=20
 annotations to the code. So I have not used it further.

I have yet to find any JVM that doesn't require >120MB to start, then there is the Clojure system and your program, so that figure doesn't surprise me. In any C/C++/Fortran context Python is the dynamic programming language if choice, but there is also Lua. Clojure programs are not good for computational efficiency on the JVM, so if that is what you are after Clojure is the wrong tool. Groovy, Scala, Java, Kotlin, Ceylon form the choice set in that context. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 28 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Fri, 2012-12-28 at 09:37 +0100, evilrat wrote:
[=E2=80=A6]
 well one of the points of immutable data is safely sharing across=20
 threads(the point there is that data once allocated doesn't=20
 changes so no need to sync it), functional languages also claims=20
 that they provides easy concurrency(if not "automagically"), but=20
 i can't say how it's really "easy" since i mostly do imperative=20
 and object programming.

Functional programming languages providing parallelism "for free" is a deep issue. Given the computational model of graph reduction, the whole concept of parallelism is different from that of JVM-based and native languages. OCaml has a GIL and so cannot handle single process multi-threaded parallelism. Haskell has real problems with parallelism because it is lazy: without manually structuring the sparks, you get all the computation on the master thread no mater what. Simon Peyton Jones and Simon Marlow have created "Data Parallel Haskell" which makes data parallel computations in Haskell very parallel and very fast. Actor, dataflow, CSP, fork-join style parallelism is difficult in pure functional languages. Clojure has made best inroads on this by employing the features of the JVM in a Lisp context. =20 --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 28 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Fri, 2012-12-28 at 10:53 +0100, deadalnix wrote:
[=E2=80=A6]
 It depends what you mean by functional. It seems to me that=20
 you'll find 2 major things that are usually understood as=20
 functionnal :
   - abstraction based on first class function. javascript is the=20
 perfect example here, and is functional.
   - purity and immutability.

In the most recent "Open Source Journal", Uncle Bob has stated that all you need to say is "no assignment" and you end up having to invent functional programming.
 If you have no tools to enforce immutability, you need to=20
 completely break abstraction to get the benefit. This is bug=20
 prone and will not scale (without abstraction nothing big is=20
 achievable).

I am not sure what you mean by "break abstraction" here. Nor how you get to "will not scale". Can you elaborate? Thanks. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 28 2012
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 28 December 2012 at 13:03:11 UTC, Russel Winder wrote:
 On Fri, 2012-12-28 at 10:53 +0100, deadalnix wrote:
 […]
 It depends what you mean by functional. It seems to me that 
 you'll find 2 major things that are usually understood as 
 functionnal :
   - abstraction based on first class function. javascript is 
 the perfect example here, and is functional.
   - purity and immutability.

In the most recent "Open Source Journal", Uncle Bob has stated that all you need to say is "no assignment" and you end up having to invent functional programming.

That is true. But is also quite reductive. If functional programming can solve that problem, it is also very suited for many other things, for instance event programming (where concept like immutability and purity are not that useful).
 If you have no tools to enforce immutability, you need to 
 completely break abstraction to get the benefit. This is bug 
 prone and will not scale (without abstraction nothing big is 
 achievable).

I am not sure what you mean by "break abstraction" here. Nor how you get to "will not scale". Can you elaborate? Thanks.

Sure. To make that clear I have to reintroduce the context : I was answering to a post that stated that even if the language don't support immutability, you can have immutability simply by not mutate data. To benefit from immutability, you have to be 100% sure that no piece of code will mutate the data ever. If you have no support for that, you break abstraction, because you have to know the internal of every piece of code you use, in order to know if the data are modified or not. If you have to know the internal of each piece of code you use, then abstraction is broken. If abstraction is broken, then the ability to code will be reduced as the codebase grow, to a point where nothing is maintainable anymore. When I say that it will not not scale, I'm talking about scaling the technique to a bigger codebase, not actually scaling the resulting program to bigger workload. The subject is quite big, and I have proposed a talk about it in DConf 2013 (I'm waiting for Walter to accept or reject).
Dec 28 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Russel Winder:

 In the most recent "Open Source Journal", Uncle Bob has stated 
 that all you need to say is "no assignment" and you end up
 having to invent functional programming.

Near the end of this interview, Erik Meijer shows why removing assignments is not enough if there is multi threading: http://www.youtube.com/watch?v=z0N1aZ6SnBk#t=60m0s Bye, bearophile
Dec 28 2012
prev sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Fri, 2012-12-28 at 16:38 +0100, deadalnix wrote:
[=E2=80=A6]
 Sure. To make that clear I have to reintroduce the context : I=20
 was answering to a post that stated that even if the language=20
 don't support immutability, you can have immutability simply by=20
 not mutate data.
=20
 To benefit from immutability, you have to be 100% sure that no=20
 piece of code will mutate the data ever. If you have no support=20
 for that, you break abstraction, because you have to know the=20
 internal of every piece of code you use, in order to know if the=20
 data are modified or not. If you have to know the internal of=20
 each piece of code you use, then abstraction is broken.

I am not sure I would relate this issue to abstraction per se, though it is about preconditions, postconditions and assumptions that can, or cannot, be made. I think we agree on the substance just differ on the language used to describe the concepts. =20
 If abstraction is broken, then the ability to code will be=20
 reduced as the codebase grow, to a point where nothing is=20
 maintainable anymore. When I say that it will not not scale, I'm=20
 talking about scaling the technique to a bigger codebase, not=20
 actually scaling the resulting program to bigger workload.

OK, I think we agree on substance just differ on the choice of language used to describe this situation. Here though "abstraction" and "broken abstraction" can work for me :-) This issue is one of the problems with very large Python codebases. They can be got round with functional tests, but strong discipline is needed. Ada and Modula-2 introduced a lot of good stuff! Thanks for taking the time to go into more depth.
 The subject is quite big, and I have proposed a talk about it in=20
 DConf 2013 (I'm waiting for Walter to accept or reject).

Sadly I won't be able to get to the conference: to travel on an aeroplane for longer than about 2 hours I have to lie flat for long periods. This generally means great cost, that is only affordable when someone else is paying, which usually means client-paid consultancy/training gigs. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Dec 28 2012