www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Functional Programming with D

reply qznc <qznc web.de> writes:
I wrote a small article to summarize D's suitability for functional 
programming.

http://beza1e1.tuxen.de/articles/functional_D.html

Feedback welcome! :)
Apr 13 2013
next sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Saturday, 13 April 2013 at 12:29:29 UTC, qznc wrote:
 Feedback welcome! :)
You wrote:
 While there is no syntactic sugar,
What about lambdas? http://dlang.org/expression.html#Lambda
Apr 13 2013
next sibling parent reply qznc <qznc web.de> writes:
Sat, 13 Apr 2013 15:03:51 +0200: Vladimir Panteleev wrote
 On Saturday, 13 April 2013 at 12:29:29 UTC, qznc wrote:
 While there is no syntactic sugar,
What about lambdas? http://dlang.org/expression.html#Lambda
Oh. I forgot about those. Thanks! The syntactic sugar seems to be quite diverse, since most of the FunctionLiteral is optional. As far as I understand the docs, all the following forms are valid? auto square1 = function int (int x) { return x*x; }; auto square2 = function (int x) { return x*x; }; auto square3 = (int x) { return x*x; }; auto square4 = int (int x) { return x*x; }; auto square5 = (int x) => x*x; auto square6 = x => x*x;
Apr 13 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/13/2013 05:25 PM, qznc wrote:
 Sat, 13 Apr 2013 15:03:51 +0200: Vladimir Panteleev wrote
 On Saturday, 13 April 2013 at 12:29:29 UTC, qznc wrote:
 While there is no syntactic sugar,
What about lambdas? http://dlang.org/expression.html#Lambda
Oh. I forgot about those. Thanks! The syntactic sugar seems to be quite diverse, since most of the FunctionLiteral is optional. As far as I understand the docs, all the following forms are valid? auto square1 = function int (int x) { return x*x; };
yes.
 auto square2 = function (int x) { return x*x; };
yes.
 auto square3 = (int x) { return x*x; };
yes.
 auto square4 = int (int x) { return x*x; };
no.
 auto square5 = (int x) => x*x;
yes.
 auto square6 = x => x*x;
no. (valid grammar, but you need some type annotation.) But there are more, like function(int x)=>x*x.
Apr 13 2013
next sibling parent qznc <qznc web.de> writes:
Sat, 13 Apr 2013 17:46:10 +0200: Timon Gehr wrote

 On 04/13/2013 05:25 PM, qznc wrote:
 Sat, 13 Apr 2013 15:03:51 +0200: Vladimir Panteleev wrote
 On Saturday, 13 April 2013 at 12:29:29 UTC, qznc wrote:
 While there is no syntactic sugar,
What about lambdas? http://dlang.org/expression.html#Lambda
Oh. I forgot about those. Thanks! The syntactic sugar seems to be quite diverse, since most of the FunctionLiteral is optional. As far as I understand the docs, all the following forms are valid? auto square1 = function int (int x) { return x*x; };
yes.
 auto square2 = function (int x) { return x*x; };
yes.
 auto square3 = (int x) { return x*x; };
yes.
 auto square4 = int (int x) { return x*x; };
no.
 auto square5 = (int x) => x*x;
yes.
 auto square6 = x => x*x;
no. (valid grammar, but you need some type annotation.) But there are more, like function(int x)=>x*x.
That one is not documented in the grammar. A Lambda does not start with "function" and a FunctionLiteral does not contain "=>". What is it?
Apr 13 2013
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Timon Gehr:

 auto square6 = x => x*x;
no. (valid grammar, but you need some type annotation.)
In theory a syntax like: alias square6 = x => x * x; Can be a shorthand for a template function like: auto square6(T0)(T0 x) { return x * x; } Bye, bearophile
Apr 13 2013
prev sibling parent qznc <qznc web.de> writes:
Sat, 13 Apr 2013 15:03:51 +0200: Vladimir Panteleev wrote

 On Saturday, 13 April 2013 at 12:29:29 UTC, qznc wrote:
 Feedback welcome! :)
You wrote:
 While there is no syntactic sugar,
What about lambdas? http://dlang.org/expression.html#Lambda
I added them to the article and acknowledged you. Thanks!
Apr 13 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/13/2013 05:29 AM, qznc wrote:
 I wrote a small article to summarize D's suitability for functional
 programming.

 http://beza1e1.tuxen.de/articles/functional_D.html

 Feedback welcome! :)
Nice article; thanks. :) Some quotes from the article and some notes: 1) "can qualify variables as immutable, which is similiar to C's const" D's immutable is similar to C's const only when we are talking about values: const int c_i = 42; // in C immutable d_i = 42; // in D When it is a reference though, not immutable but D's const is similar to C's const. Otherwise, there is the following difference: // in C: I have no idea whether c is immutable void foo(const int * c); // in D: I know d is immutable void foo(immutable const ref d); (Actually, not only I "know", but I "demand" that d is immutable.) 2) "if you have a function which does not mutate an argument, then qualify it const, but not immutable" I had arrived the same conclusion (and have been spreading it too :)). Actually, the choice is not that clear: If the function is going to need an immutable copy of a reference parameter anyway, then it is better that it goes ahead and takes an immutable reference parameter: void foo(immutable(int)[] numbers); The benefit is, if the caller already has an immutable slice, then that slice gets passed as the argument. That is the fastest... On the other hande, if the caller does not have an immutable slice, then the caller makes one and passes the new copy. Nothing is lost: The copy that the function would have to make has been made by caller. Although that seems like an implementation detail of the function leaking out, and it really is, it is not that bad if we view it like this: What is happening is that the function is working with its caller to get more performance. 3) "D does not allow you to cast something to immutable" I think you mean "no implicit conversion" because it is not true if we take what you said literally: auto a = [ 1, 2 ]; immutable i = cast(immutable)a; // dangerous a[0] = 42; assert(i[0] == 42); // oops: immutable element has changed! Ali
Apr 13 2013
next sibling parent "Chris Cain" <clcain uncg.edu> writes:
On Sunday, 14 April 2013 at 00:38:24 UTC, Ali Çehreli wrote:
 3) "D does not allow you to cast something to immutable"

 I think you mean "no implicit conversion" because it is not 
 true if we take what you said literally:

     auto a = [ 1, 2 ];
     immutable i = cast(immutable)a;  // dangerous

     a[0] = 42;
     assert(i[0] == 42);  // oops: immutable element has changed!

 Ali
Also, the usual way to do this (if you're doing it _properly_, this is still vulnerable to being misused) is using `assumeUnique` ... the "requirements" for that function are implied by its name: it really wants a unique reference that will be transformed into an immutable. ``` import std.exception : assumeUnique; static immutable size_t base = cast(size_t) ('z' - 'a') + 1; // Remember: // alias string = immutable(char)[] string numToString(size_t length, size_t num) { char[] result = new char[](length); foreach_reverse(ref e; result) { auto digit = num % base; e = cast(char)('a' + digit); num /= base; } // OK because no other references exist return assumeUnique(result); } ```
Apr 13 2013
prev sibling parent reply qznc <qznc web.de> writes:
Sat, 13 Apr 2013 17:38:24 -0700: Ali Çehreli wrote

 On 04/13/2013 05:29 AM, qznc wrote:
 I wrote a small article to summarize D's suitability for functional
 programming.

 http://beza1e1.tuxen.de/articles/functional_D.html

 Feedback welcome! :)
Nice article; thanks. :) Some quotes from the article and some notes: 1) "can qualify variables as immutable, which is similiar to C's const" D's immutable is similar to C's const only when we are talking about values: const int c_i = 42; // in C immutable d_i = 42; // in D When it is a reference though, not immutable but D's const is similar to C's const. Otherwise, there is the following difference: // in C: I have no idea whether c is immutable void foo(const int * c); // in D: I know d is immutable void foo(immutable const ref d); (Actually, not only I "know", but I "demand" that d is immutable.)
The C variant is an mutable pointer to an immutable int. What is not to know about that?
 2) "if you have a function which does not mutate an argument, then
 qualify it const, but not immutable"
 
 I had arrived the same conclusion (and have been spreading it too :)).
 
 Actually, the choice is not that clear: If the function is going to need
 an immutable copy of a reference parameter anyway, then it is better
 that it goes ahead and takes an immutable reference parameter:
 
      void foo(immutable(int)[] numbers);
 
 The benefit is, if the caller already has an immutable slice, then that
 slice gets passed as the argument. That is the fastest... On the other
 hande, if the caller does not have an immutable slice, then the caller
 makes one and passes the new copy. Nothing is lost: The copy that the
 function would have to make has been made by caller.
 
 Although that seems like an implementation detail of the function
 leaking out, and it really is, it is not that bad if we view it like
 this: What is happening is that the function is working with its caller
 to get more performance.
I agree with you. However, it is too much detail for the article.
 3) "D does not allow you to cast something to immutable"
 
 I think you mean "no implicit conversion" because it is not true if we
 take what you said literally:
 
      auto a = [ 1, 2 ];
      immutable i = cast(immutable)a;  // dangerous
 
      a[0] = 42;
      assert(i[0] == 42);  // oops: immutable element has changed!
I clarified this in the article. Thanks for pointing it out. :)
Apr 13 2013
next sibling parent "anonymous" <anonymous example.com> writes:
On Sunday, 14 April 2013 at 06:35:53 UTC, qznc wrote:
 Sat, 13 Apr 2013 17:38:24 -0700: Ali Çehreli wrote
[...]
 When it is a reference though, not immutable but D's const is 
 similar to
 C's const. Otherwise, there is the following difference:
 
      // in C: I have no idea whether c is immutable void 
 foo(const int *
      c);
 
      // in D: I know d is immutable void foo(immutable const 
 ref d);
 
 (Actually, not only I "know", but I "demand" that d is 
 immutable.)
The C variant is an mutable pointer to an immutable int. What is not to know about that?
You can pass a pointer to a mutable int to the C version foo. You can't do that with D's immutable.
Apr 14 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/13/2013 11:35 PM, qznc wrote:

 D's immutable is similar to C's const only when we are talking about
 values:

       const int c_i = 42;    // in C immutable d_i = 42;    // in D

 When it is a reference though, not immutable but D's const is similar to
 C's const. Otherwise, there is the following difference:

       // in C: I have no idea whether c is immutable void foo(const 
int *
       c);

       // in D: I know d is immutable void foo(immutable const ref d);

 (Actually, not only I "know", but I "demand" that d is immutable.)
The C variant is an mutable pointer to an immutable int. What is not to know about that?
What foo() does not know is whether the original int is const or not: int i = 0; foo(&i); // Can be mutated by the caller later on i = 1; For that reason, function foo() cannot store the pointer 'c' in confidence that it will not change in the future. Of course you and the dlang.org link that you have provided indicate that immutable is not the same as const. When you say "You can qualify variables as immutable, which is similiar to C's const and Java's final, but it is transitive", it sounds like the main difference that brings 'immutable' is transitivity but I think the fact that data cannot be mutated is the main difference. That makes it possible for a function to request immutable data, something not possible in C because a const reference parameter is not a requirement but a promise not to mutate. And of course you never say they are the same; you say "similar". Nothing is wrong with that. :) Ali
Apr 14 2013
parent reply "Kingsley" <kingsley.hendrickse gmail.com> writes:
On Sunday, 14 April 2013 at 15:27:29 UTC, Ali Çehreli wrote:
 On 04/13/2013 11:35 PM, qznc wrote:

 [...]
talking about
       [...]
// in D
 [...]
is similar to
       [...]
foo(const int *
       [...]
const ref d);
 [...]
immutable.)
 The C variant is an mutable pointer to an immutable int. What
is not to
 know about that?
What foo() does not know is whether the original int is const or not: int i = 0; foo(&i); // Can be mutated by the caller later on i = 1; For that reason, function foo() cannot store the pointer 'c' in confidence that it will not change in the future. Of course you and the dlang.org link that you have provided indicate that immutable is not the same as const. When you say "You can qualify variables as immutable, which is similiar to C's const and Java's final, but it is transitive", it sounds like the main difference that brings 'immutable' is transitivity but I think the fact that data cannot be mutated is the main difference. That makes it possible for a function to request immutable data, something not possible in C because a const reference parameter is not a requirement but a promise not to mutate. And of course you never say they are the same; you say "similar". Nothing is wrong with that. :) Ali
This is excellent information on functional programming with D. I would love to see a lot more information in this area - perhaps a much longer article covering in more detail - and also covering what is missing - e.g. does D have a for comprehension, Option, Either etc
Aug 27 2015
parent Russel Winder via Digitalmars-d-announce writes:
On Fri, 2015-08-28 at 06:45 +0000, Kingsley via Digitalmars-d-announce
wrote:
=20
[=E2=80=A6]
 This is excellent information on functional programming with D. I=20
 would love to see a lot more information in this area - perhaps a=20
 much longer article covering in more detail - and also covering=20
 what is missing - e.g. does D have a for comprehension, Option,=20
 Either etc
"For comprehensions" are (more less) just ways of doing lazy sequence comprehensions in Scala, Clojure, etc. I think I prefer comprehensions in the Miranda, Haskell, Python, etc. style: generator expression are handled with constructs that do not resemble explicit iteration for loops. Less to create confusion. --=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.net 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
Aug 28 2015