From: Florian Frank Date: 2002-10-22T11:02:30+09:00 Subject: Re: Difference between inject and reduce Am 2002-10-22 04:34:32 +0900 schrieb Travis Whitton: > Lately I've been trying to learn more about functional programming and > understand more about ruby's functional features in the process. In > studying SML, I've come across a function called reduce, which seems > very similar to ruby's inject method. I've defined reduce in ruby as > follows: > > def reduce(f, b, list) > if (list.empty?) > b > else > f.call(list.first, reduce(f, b, list[1, list.length])) > end > end > > Am I correct in assuming the only difference between reduce and the > inject method described in the pickaxe book is that reduce takes an > anonymous method as an argument rather than inserting a block via > yield? You could also use a Proc object with inject: m = lambda { |x,y| x - y } ==># (1..10).inject(0, &m) ==>-55 There's a more important difference with m, because reduce returns another value: reduce(m, 0, list(*(1..10))) ==>-5 inject and reduce return equal values if the function is commutative. If it isn't (like m), they differ. You can see why if you go through the steps in a calculation for a small example. inject is more similiar to accumulate: def accumulate(fun, x, list) if null?(list) x else accumulate(fun, fun.call(x, car(list)), cdr(list)) end end But inject is implemented iterative in C, because recursion isn't as efficient in Ruby as in FP languages which grok tail recursion. BTW: I've implemented some of the usual functions used in FP as a fun project in Ruby: http://www.ping.de/~flori/programs.shtml#functional Archive: http://www.ping.de/~flori/programs/ruby/functional/functional.tgz Module in Pretty HTML: http://www.ping.de/~flori/programs/ruby/functional/func.rb.html During this project I found out that 1. this is valid Ruby code (def accumulate (fun, x, list) (if (null? list) x else (accumulate fun, (fun.call x, (car list)), (cdr list)) end) end) and 2. that ":set syntax=lisp" in vim while programming Ruby is very useful in some cases. *g* > Also, when using ruby in a functional style is there a better way to > get the traditional car and cdr of an Array than array.first, array[1, > array.length]? I understand that an array is not the same thing as a > "list", but I'm just thinking convience here. Perhaps like that: first, *list = list But it is only shorter not more efficient I think. -- Give me a man or a woman who has read a thousand books and you give me an interesting companion. Give me a man or a woman who has read perhaps three and you give me a dangerous enemy indeed. -- Anne Rice, "The witching hour"