December 26, 2012
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.

December 26, 2012
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
December 26, 2012
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...
December 26, 2012
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
December 26, 2012
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.
December 26, 2012
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
December 26, 2012
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.


December 26, 2012
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).
December 26, 2012
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.
December 26, 2012
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