in reply to Re^7: Specializing Functions with Currying
in thread Specializing Functions with Currying

Actually programming languages that understand tail-recursion would have made stvn's solution both elegant and efficient.

That said, some algorithms just cannot be efficiently implemented in a "pure" functional manner. A good example is the Sieve of Eratosthenes.

  • Comment on Re^8: Specializing Functions with Currying

Replies are listed 'Best First'.
Re^9: Specializing Functions with Currying
by hardburn (Abbot) on Aug 09, 2004 at 13:08 UTC

    Something I've noticed in some of my own (brief) studies into functional programming is that it tends to make one think in algorithms that are not always the most efficient, and sometimes tail-recursion won't save you.

    For instance, in a SoPW a while back, a poster wanted an efficient way to get the highest number in a list (or something along those lines). I posted this solution:

    my $highest = pop sort { $a <=> $b } @list;

    For some reason, my brain was convinced that this was the most efficient solution. While it may be a wonderful bit of functional code, it is not nearly as efficient as the iterative solution I knew quite well when I was a new C programmer:

    my $highest = pop @list; foreach (@list) { $highest = $_ if $_ > $highest; }

    Just what was I thinking?

    I guess this is a warning not to rely on any one tool too much.

    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

      Oh, that solution can be quite efficient. You just have to generalize the problem in the right way. :-)

      An example where the moral equivalent of your approach is efficient is if you want the top m elements out of a set of n. Make the sort be a lazy sort (eg heapsort) so that you only do the necessary comparisons. The efficiency is then O(n+m*log(n)), which is about as good as you will get.

      If you write bad functional code, that does not imply the of failure functional programming.

      What were you thinking, indeed?

      use List::Util qw(reduce); my $highest = reduce { $a > $b ? $a : $b } @list;

      Of course, in practice, you'd use the specialized max() function from the module — but the above is how you'd write this algorithm in any functional language.

      The fact that you wrote the sort solution in functional style is a red herring — you can just as well write a sort solution in imperative style.

      Makeshifts last the longest.

      While it may be a wonderful bit of functional code, it is not nearly as efficient as the iterative solution

      While it is functional, I wouldn't describe it as wonderful :-) A functional developer would use reduce to do it efficiently

      I sometimes fall foul of that too. My most recent example was:

      my $first = first{ length > 3 } @array; print $first;

      Versus:

      my $first; for ( @array ) { next unless length > 3; $first = $_; last; } print $first;

      where, despite the compiled-loop nature of List::Util::first, the latter was considerably more efficient than the former if the required value was close to the front of the array.

      Nearly twice as efficient with an array of 100,000 items and the thing I was looking for about a 10th of the way in.

      Funnily enough, even if the item I was looking for was the last item in the array, the iterative approach was still quickest. I guess the penalty of entering and exiting the block scope is the cause?


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon

        first is pure-Perl and does not have short-circuiting behaviour.

        Use the source, Luke. It's what it's there for. :-)

        Makeshifts last the longest.