Catamorphism: Difference between revisions
(Nimrod -> Nim) |
|||
Line 450: | Line 450: | ||
# let product = List.fold_left ( * ) 1 nums;; |
# let product = List.fold_left ( * ) 1 nums;; |
||
val product : int = 3628800</lang> |
val product : int = 3628800</lang> |
||
=={{header|Oforth}}== |
|||
reduce is already defined into Collection class : |
|||
<lang Oforth>[ 1, 2, 3, 4, 5 ] reduce(#max) |
|||
[ "abc", "def", "gfi" ] reduce(#+)</lang> |
|||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
Revision as of 11:26, 12 January 2015
You are encouraged to solve this task according to the task description, using any language you may know.
Reduce is a function or method that is used to take the values in an array or a list and apply a function to successive members of the list to produce (or reduce them to), a single value.
Show how reduce (or foldl or foldr etc), work (or would be implemented) in your language.
- Cf.
Ada
<lang Ada>with Ada.Text_IO;
procedure Catamorphism is
type Fun is access function (Left, Right: Natural) return Natural; type Arr is array(Natural range <>) of Natural; function Fold_Left (F: Fun; A: Arr) return Natural is Result: Natural := A(A'First); begin for I in A'First+1 .. A'Last loop
Result := F(Result, A(I));
end loop; return Result; end Fold_Left; function Max (L, R: Natural) return Natural is (if L > R then L else R); function Min (L, R: Natural) return Natural is (if L < R then L else R); function Add (Left, Right: Natural) return Natural is (Left + Right); function Mul (Left, Right: Natural) return Natural is (Left * Right); package NIO is new Ada.Text_IO.Integer_IO(Natural);
begin
NIO.Put(Fold_Left(Min'Access, (1,2,3,4)), Width => 3); NIO.Put(Fold_Left(Max'Access, (1,2,3,4)), Width => 3); NIO.Put(Fold_Left(Add'Access, (1,2,3,4)), Width => 3); NIO.Put(Fold_Left(Mul'Access, (1,2,3,4)), Width => 3);
end Catamorphism;</lang>
- Output:
1 4 10 24
Bracmat
<lang bracmat>( ( fold
= f xs init first rest . !arg:(?f.?xs.?init) & ( !xs:&!init | !xs:%?first ?rest & !f$(!first.fold$(!f.!rest.!init)) ) )
& out
$ ( fold $ ( (=a b.!arg:(?a.?b)&!a+!b) . 1 2 3 4 5 . 0 ) )
& (product=a b.!arg:(?a.?b)&!a*!b) & out$(fold$(product.1 2 3 4 5.1)) );</lang> Output:
15 120
C
<lang C>#include <stdio.h>
typedef int (*intFn)(int, int);
int reduce(intFn fn, int size, int *elms) {
int i, val = *elms; for (i = 1; i < size; ++i) val = fn(val, elms[i]); return val;
}
int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; }
int main(void) {
int nums[] = {1, 2, 3, 4, 5}; printf("%d\n", reduce(add, 5, nums)); printf("%d\n", reduce(sub, 5, nums)); printf("%d\n", reduce(mul, 5, nums)); return 0;
}</lang>
- Output:
15 -13 120
C++
<lang cpp>#include <iostream>
- include <numeric>
- include <functional>
- include <vector>
int main() { std::vector<int> nums = { 1, 2, 3, 4, 5 }; auto nums_added = std::accumulate(std::begin(nums), std::end(nums), 0, std::plus<int>()); auto nums_other = std::accumulate(std::begin(nums), std::end(nums), 0, [](const int& a, const int& b) { return a + 2 * b; }); std::cout << "nums_added: " << nums_added << std::endl; std::cout << "nums_other: " << nums_other << std::endl; }</lang>
- Output:
nums_added: 15 nums_other: 30
C#
<lang csharp>var nums = Enumerable.Range(1, 10);
int summation = nums.Aggregate((a, b) => a + b);
int product = nums.Aggregate((a, b) => a * b);
string concatenation = nums.Aggregate(String.Empty, (a, b) => a.ToString() + b.ToString());
Console.WriteLine("{0} {1} {2}", summation, product, concatenation);</lang>
Clojure
For more detail, check Rich Hickey's blog post on Reducers.
<lang clojure>; Basic usage > (reduce * '(1 2 3 4 5)) 120
- Using an initial value
> (reduce + 100 '(1 2 3 4 5)) 115 </lang>
Common Lisp
<lang lisp>; Basic usage > (reduce #'* '(1 2 3 4 5)) 120
- Using an initial value
> (reduce #'+ '(1 2 3 4 5) :initial-value 100) 115
- Using only a subsequence
> (reduce #'+ '(1 2 3 4 5) :start 1 :end 4) 9
- Apply a function to each element first
> (reduce #'+ '((a 1) (b 2) (c 3)) :key #'cadr) 6
- Right-associative reduction
> (reduce #'expt '(2 3 4) :from-end T) 2417851639229258349412352
- Compare with
> (reduce #'expt '(2 3 4)) 4096</lang>
D
<lang d>void main() {
import std.stdio, std.algorithm, std.range, std.numeric, std.conv, std.typecons, std.typetuple;
auto list = iota(1, 11); alias ops = TypeTuple!(q{a + b}, q{a * b}, min, max, gcd);
foreach (op; ops) writeln(op.stringof, ": ", list.reduce!op);
// std.algorithm.reduce supports multiple functions in parallel: reduce!(ops[0], ops[3], text)(tuple(0, 0.0, ""), list).writeln;
}</lang>
- Output:
"a + b": 55 "a * b": 3628800 min(T1,T2,T...) if (is(typeof(a < b))): 1 max(T1,T2,T...) if (is(typeof(a < b))): 10 gcd(T): 1 Tuple!(int,double,string)(55, 10, "12345678910")
Déjà Vu
This is a foldl: <lang dejavu>reduce f lst init: if lst: f reduce @f lst init pop-from lst else: init
!. reduce @+ [ 1 10 200 ] 4 !. reduce @- [ 1 10 200 ] 4 </lang>
- Output:
215 -207
Go
<lang go>package main
import ( "fmt" )
func main() { n := []int{1, 2, 3, 4, 5}
fmt.Println(reduce(add, n)) fmt.Println(reduce(sub, n)) fmt.Println(reduce(mul, n)) }
func add(a int, b int) int { return a + b } func sub(a int, b int) int { return a - b } func mul(a int, b int) int { return a * b }
func reduce(rf func(int, int) int, m []int) int { r := m[0] for _, v := range m[1:] { r = rf(r, v) } return r }</lang>
- Output:
15 -13 120
Haskell
<lang haskell>nums = [1..10]
summation = foldl (+) 0 nums product = foldl (*) 1 nums concatenation = foldr (\num s -> show num ++ s) "" nums</lang>
There is are also foldl1 and foldr1 available that implicitly take first element as starting value. However they are not safe as they fail on empty lists.
Prelude folds work only on lists, module Data.Foldable a typeclass for more general fold - interface remains the same.
Icon and Unicon
Works in both languages: <lang unicon>procedure main(A)
write(A[1],": ",curry(A[1],A[2:0]))
end
procedure curry(f,A)
r := A[1] every r := f(r, !A[2:0]) return r
end</lang>
Sample runs:
->cata + 3 1 4 1 5 9 +: 23 ->cata - 3 1 4 1 5 9 -: -17 ->cata \* 3 1 4 1 5 9 *: 540 ->cata "||" 3 1 4 1 5 9 ||: 314159
J
Solution:<lang j> /</lang> Example:<lang j> +/ 1 2 3 4 5 15
*/ 1 2 3 4 5
120
!/ 1 2 3 4 5 NB. "n ! k" is "n choose k"
45</lang>
Java
<lang java>import java.util.stream.Stream;
public class ReduceTask {
public static void main(String[] args) { System.out.println(Stream.of(1, 2, 3, 4, 5).mapToInt(i -> i).sum()); System.out.println(Stream.of(1, 2, 3, 4, 5).reduce(1, (a, b) -> a * b)); }
}</lang>
- Output:
15 120
JavaScript
<lang javascript>var nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function add(a, b) {
return a + b;
}
var summation = nums.reduce(add);
function mul(a, b) {
return a * b;
}
var product = nums.reduce(mul, 1);
var concatenation = nums.reduce(add, "");
console.log(summation, product, concatenation);</lang>
jq
jq has an unusual and unusually powerful "reduce" control structure. A full description is beyond the scope of this short article, but an important point is that "reduce" is stream-oriented. Reduction of arrays is however trivially achieved using the "[]" filter for converting an array to a stream of its values.
The simplest use of "reduce" can be illustrated by this definition of "factorial":
def factorial: reduce range(2;.+1) as $i (1; . * $i);
If the input is a non-negative integer, n, this will compute n!.
To understand how this works, consider "3|factorial". The computation starts by setting the implicit state variable to 1; range(2;4) will generate the sequence of values (2,3). The variable $i is set to each value in the stream in turn so that the state variable is multiplied by 2 (". * $i") and then by 3. Notice that since range/2 produces a stream, no array is ever constructed.
For a more complex illustration, see Strand sort.
The "reduce" operator is typically used within a map/reduce framework, but the implicit state variable can be any JSON entity, and so "reduce" is also a general-purpose iterative control structure, the only limitation being that it does not have the equivalent of "break". For that, the "foreach" control structure in recent versions of jq can be used.
Logtalk
The Logtalk standard library provides implementations of common meta-predicates such as fold left. The example that follow uses Logtalk's native support for lambda expressions to avoid the need for auxiliary predicates. <lang logtalk>
- - object(folding_examples).
:- public(show/0). show :- integer::sequence(1, 10, List), write('List: '), write(List), nl, meta::fold_left([Acc,N,Sum0]>>(Sum0 is Acc+N), 0, List, Sum), write('Sum of all elements: '), write(Sum), nl, meta::fold_left([Acc,N,Product0]>>(Product0 is Acc*N), 1, List, Product), write('Product of all elements: '), write(Product), nl, meta::fold_left([Acc,N,Concat0]>>(number_codes(N,NC), atom_codes(NA,NC), atom_concat(Acc,NA,Concat0)), , List, Concat), write('Concatenation of all elements: '), write(Concat), nl.
- - end_object.
</lang>
- Output:
| ?- folding_examples::show. List: [1,2,3,4,5,6,7,8,9,10] Sum of all elements: 55 Product of all elements: 3628800 Concatenation of all elements: 12345678910 yes
LOLCODE
<lang LOLCODE>HAI 1.3
HOW IZ I reducin YR array AN YR size AN YR fn
I HAS A val ITZ array'Z SRS 0 IM IN YR loop UPPIN YR i TIL BOTH SAEM i AN DIFF OF size AN 1 val R I IZ fn YR val AN YR array'Z SRS SUM OF i AN 1 MKAY IM OUTTA YR loop FOUND YR val
IF U SAY SO
O HAI IM array
I HAS A SRS 0 ITZ 1 I HAS A SRS 1 ITZ 2 I HAS A SRS 2 ITZ 3 I HAS A SRS 3 ITZ 4 I HAS A SRS 4 ITZ 5
KTHX
HOW IZ I add YR a AN YR b, FOUND YR SUM OF a AN b, IF U SAY SO HOW IZ I sub YR a AN YR b, FOUND YR DIFF OF a AN b, IF U SAY SO HOW IZ I mul YR a AN YR b, FOUND YR PRODUKT OF a AN b, IF U SAY SO
VISIBLE I IZ reducin YR array AN YR 5 AN YR add MKAY VISIBLE I IZ reducin YR array AN YR 5 AN YR sub MKAY VISIBLE I IZ reducin YR array AN YR 5 AN YR mul MKAY
KTHXBYE</lang>
- Output:
15 -13 120
Maple
The left fold operator in Maple is foldl, and foldr is the right fold operator. <lang Maple>> nums := seq( 1 .. 10 );
nums := 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
> foldl( `+`, 0, nums ); # compute sum using foldl
55
> foldr( `*`, 1, nums ); # compute product using foldr
3628800</lang>
Compute the horner form of a (sorted) polynomial: <lang Maple>> foldl( (a,b) ->a*T+b, op(map2(op,1,[op( 72*T^5+37*T^4-23*T^3+87*T^2+44*T+29 )])));
((((72 T + 37) T - 23) T + 87) T + 44) T + 29</lang>
Mathematica
<lang mathematica>Fold[f, x, {a, b, c, d}]</lang>
- Output:
f[f[f[f[x, a], b], c], d]
Maxima
<lang maxima>lreduce(f, [a, b, c, d], x0); /* (%o1) f(f(f(f(x0, a), b), c), d) */</lang>
<lang maxima>lreduce("+", [1, 2, 3, 4], 100); /* (%o1) 110 */</lang>
Nemerle
The Nemerle.Collections namespace defines FoldLeft, FoldRight and Fold (an alias for FoldLeft) on any sequence that implements the IEnumerable[T] interface. <lang Nemerle>def seq = [1, 4, 6, 3, 7]; def sum = seq.Fold(0, _ + _); // Fold takes an initial value and a function, here the + operator</lang>
Nim
<lang nim>import sequtils
block:
let numbers = @[5, 9, 11] addition = foldl(numbers, a + b) substraction = foldl(numbers, a - b) multiplication = foldl(numbers, a * b) words = @["nim", "rod", "is", "cool"] concatenation = foldl(words, a & b)
block:
let numbers = @[5, 9, 11] addition = foldr(numbers, a + b) substraction = foldr(numbers, a - b) multiplication = foldr(numbers, a * b) words = @["nim", "rod", "is", "cool"] concatenation = foldr(words, a & b)</lang>
OCaml
<lang ocaml># let nums = [1;2;3;4;5;6;7;8;9;10];; val nums : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
- let sum = List.fold_left (+) 0 nums;;
val sum : int = 55
- let product = List.fold_left ( * ) 1 nums;;
val product : int = 3628800</lang>
Oforth
reduce is already defined into Collection class :
<lang Oforth>[ 1, 2, 3, 4, 5 ] reduce(#max) [ "abc", "def", "gfi" ] reduce(#+)</lang>
PARI/GP
<lang parigp>reduce(f, v)={
my(t=v[1]); for(i=2,#v,t=f(t,v[i])); t
}; reduce((a,b)->a+b, [1,2,3,4,5,6,7,8,9,10])</lang>
<lang parigp>fold((a,b)->a+b, [1..10])</lang>
Pascal
Should work with many pascal dialects <lang pascal>program reduce;
type // tmyArray = array of LongInt;
tmyArray = array[-5..5] of LongInt; tmyFunc = function (a,b:LongInt):LongInt;
function add(x,y:LongInt):LongInt; begin
add := x+y;
end;
function sub(k,l:LongInt):LongInt; begin
sub := k-l;
end;
function mul(r,t:LongInt):LongInt; begin
mul := r*t;
end;
function reduce(myFunc:tmyFunc;a:tmyArray):LongInt; var
i,res : LongInt;
begin
res := a[low(a)]; For i := low(a)+1 to high(a) do res := myFunc(res,a[i]); reduce := res;
end;
procedure InitMyArray(var a:tmyArray); var
i: LongInt;
begin
For i := low(a) to high(a) do begin //no a[i] = 0 a[i] := i + ord(i=0); write(a[i],','); end; writeln(#8#32);
end;
var
ma : tmyArray;
BEGIN
InitMyArray(ma); writeln(reduce(@add,ma)); writeln(reduce(@sub,ma)); writeln(reduce(@mul,ma));
END.</lang> output
-5,-4,-3,-2,-1,1,1,2,3,4,5 1 -11 -1440
Perl
Perl's reduce function is in a standard package. <lang perl>use List::Util 'reduce';
- note the use of the odd $a and $b globals
print +(reduce {$a + $b} 1 .. 10), "\n";
- first argument is really an anon function; you could also do this:
sub func { $b & 1 ? "$a $b" : "$b $a" } print +(reduce \&func, 1 .. 10), "\n"</lang>
Perl 6
Any associative infix operator, either built-in or user-defined, may be turned into a reduce operator by putting it into square brackets (known as "the reduce metaoperator") and using it as a list operator. The operations will work left-to-right or right-to-left automatically depending on the natural associativity of the base operator. <lang perl6>my @list = 1..10; say [+] @list; say [*] @list; say [~] @list; say [min] @list; say [max] @list; say [lcm] @list;</lang>
- Output:
55 3628800 12345678910 1 10 2520
In addition to the reduce metaoperator, a general higher-order function, reduce, can apply any appropriate function. Reproducing the above in this form, using the function names of those operators, we have: <lang perl6>say reduce &infix:<+>, @list; say reduce &infix:<*>, @list; say reduce &infix:<~>, @list; say reduce &infix:<min>, @list; say reduce &infix:<max>, @list; say reduce &infix:<lcm>, @list;</lang>
PicoLisp
<lang PicoLisp>(de reduce ("Fun" "Lst")
(let "A" (car "Lst") (for "N" (cdr "Lst") (setq "A" ("Fun" "A" "N")) ) "A" ) )
(println
(reduce + (1 2 3 4 5)) (reduce * (1 2 3 4 5)) )
(bye)</lang>
Prolog
SWI-Prolog has native foldl in version 6.3.1
Module lambda was written by Ulrich Neumerkel and can be found there http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl
<lang Prolog>:- use_module(library(lambda)).
% foldl is now a predicate of SWI-Prolog 6.3.1 % catamorphism :- numlist(1,10,L), foldl(\XS^YS^ZS^(ZS is XS+YS), L, 0, Sum), format('Sum of ~w is ~w~n', [L, Sum]), foldl(\XP^YP^ZP^(ZP is XP*YP), L, 1, Prod), format('Prod of ~w is ~w~n', [L, Prod]), string_to_list(LV, ""), foldl(\XC^YC^ZC^(string_to_atom(XS, XC),string_concat(YC,XS,ZC)), L, LV, Concat), format('Concat of ~w is ~w~n', [L, Concat]).</lang>
- Output:
?- catamorphism. Sum of [1,2,3,4,5,6,7,8,9,10] is 55 Prod of [1,2,3,4,5,6,7,8,9,10] is 3628800 Concat of [1,2,3,4,5,6,7,8,9,10] is 12345678910 true.
Python
<lang python>>>> from operator import add >>> listoflists = [['the', 'cat'], ['sat', 'on'], ['the', 'mat']] >>> help(reduce) Help on built-in function reduce in module __builtin__:
reduce(...)
reduce(function, sequence[, initial]) -> value Apply a function of two arguments cumulatively to the items of a sequence, from left to right, so as to reduce the sequence to a single value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates ((((1+2)+3)+4)+5). If initial is present, it is placed before the items of the sequence in the calculation, and serves as a default when the sequence is empty.
>>> reduce(add, listoflists, []) ['the', 'cat', 'sat', 'on', 'the', 'mat'] >>> </lang>
Additional example
<lang python>from functools import reduce from operator import add, mul
nums = range(1,11)
summation = reduce(add, nums)
product = reduce(mul, nums)
concatenation = reduce(lambda a, b: str(a) + str(b), nums)
print(summation, product, concatenation)</lang>
Racket
<lang racket>
- lang racket
(define (fold f xs init)
(if (empty? xs) init (f (first xs) (fold f (rest xs) init))))
(fold + '(1 2 3) 0) ; the result is 6 </lang>
REXX
This REXX example is modeled after the Perl 6 example (it is NOT a translation). <lang rexx>/*REXX pgm shows a method for catamorphism for some simple functions. */ @list = 1 2 3 4 5 6 7 8 9 10
say 'show:' fold(@list, 'show') say ' sum:' fold(@list, '+') say 'prod:' fold(@list, '*') say ' cat:' fold(@list, '||') say ' min:' fold(@list, 'min') say ' max:' fold(@list, 'max') say ' avg:' fold(@list, 'avg') say ' GCD:' fold(@list, 'GCD') say ' LCM:' fold(@list, 'LCM')
exit /*stick a fork in it, we're done.*/ /*──────────────────────────────────FOLD subroutine─────────────────────*/ fold: procedure; parse arg z; arg ,f; z=space(z) /*F is uppercased.*/ za=translate(z, f, " "); zf=f'('translate(z,',' ," ")')' if f=='+' | f=='*' then interpret 'return' za if f=='||' then return space(z,0) if f=='AVG' then interpret 'return' fold(z,'+') "/" words(z) if wordpos(f,'MIN MAX LCM GCD')\==0 then interpret 'return' zf if f=='SHOW' then return z return 'illegal function:' arg(2) /*──────────────────────────────────LCM subroutine──────────────────────*/ lcm: procedure; $=; do j=1 for arg(); $=$ arg(j); end x=abs(word($,1)) /* [↑] build a list of arguments.*/
do k=2 to words($); !=abs(word($,k)); if !=0 then return 0 x=x*! / gcd(x,!) /*have GCD do the heavy lifting.*/ end /*k*/
return x /*return with the money. */ /*──────────────────────────────────GCD subroutine──────────────────────*/ gcd: procedure; $=; do j=1 for arg(); $=$ arg(j); end parse var $ x z .; if x=0 then x=z /* [↑] build a list of arguments.*/ x=abs(x)
do k=2 to words($); y=abs(word($,k)); if y=0 then iterate do until _==0; _=x//y; x=y; y=_; end /*until*/ end /*k*/
return x /*return with the money. */</lang>
- Output:
list: 1 2 3 4 5 6 7 8 9 10 sum: 55 prod: 3628800 cat: 12345678910 min: 1 max: 10 avg: 5.5 GCD: 1 LCM: 2520
Ruby
The method inject (and it's alias reduce) can be used in several ways; the simplest is to give a methodname as argument: <lang ruby># sum: p (1..10).inject(:+)
- smallest number divisible by all numbers from 1 to 20:
p (1..20).inject(:lcm) #lcm: lowest common multiple </lang>The most versatile way uses a accumulator object (memo) and a block. In this example Pascal's triangle is generated by using an array [1,1] and inserting the sum of each consecutive pair of numbers from the previous row. <lang ruby>p row = [1] 10.times{p row = row.each_cons(2).inject([1,1]){|ar,(a,b)| ar.insert(-2, a+b)} }
- [1]
- [1, 1]
- [1, 2, 1]
- [1, 3, 3, 1]
- [1, 4, 6, 4, 1]
- [1, 5, 10, 10, 5, 1]
- [1, 6, 15, 20, 15, 6, 1]
- etc
</lang>
Run BASIC
<lang runbasic>for i = 1 to 10 :n(i) = i:next i
print " +: ";" ";cat(10,"+") print " -: ";" ";cat(10,"-") print " *: ";" ";cat(10,"*") print " /: ";" ";cat(10,"/") print " ^: ";" ";cat(10,"^") print "min: ";" ";cat(10,"min") print "max: ";" ";cat(10,"max") print "avg: ";" ";cat(10,"avg") print "cat: ";" ";cat(10,"cat")
function cat(count,op$) cat = n(1) for i = 2 to count
if op$ = "+" then cat = cat + n(i) if op$ = "-" then cat = cat - n(i) if op$ = "*" then cat = cat * n(i) if op$ = "/" then cat = cat / n(i) if op$ = "^" then cat = cat ^ n(i) if op$ = "max" then cat = max(cat,n(i)) if op$ = "min" then cat = min(cat,n(i)) if op$ = "avg" then cat = cat + n(i) if op$ = "cat" then cat$ = cat$ + str$(n(i))
next i if op$ = "avg" then cat = cat / count if op$ = "cat" then cat = val(str$(n(1))+cat$) end function</lang>
+: 55 -: -53 *: 3628800 /: 2.75573205e-7 ^: 1 min: 1 max: 10 avg: 5.5 cat: 12345678910
Sidef
<lang ruby>say (1..10 -> reduce('+')); say (1..10 -> reduce{|a,b| a + b});</lang>
Standard ML
<lang sml>- val nums = [1,2,3,4,5,6,7,8,9,10]; val nums = [1,2,3,4,5,6,7,8,9,10] : int list - val sum = foldl op+ 0 nums; val sum = 55 : int - val product = foldl op* 1 nums; val product = 3628800 : int</lang>
Tcl
Tcl does not come with a built-in fold command, but it is easy to construct: <lang tcl>proc fold {lambda zero list} {
set accumulator $zero foreach item $list {
set accumulator [apply $lambda $accumulator $item]
} return $accumulator
}</lang> Demonstrating: <lang tcl>set 1to5 {1 2 3 4 5}
puts [fold {{a b} {expr {$a+$b}}} 0 $1to5] puts [fold {{a b} {expr {$a*$b}}} 1 $1to5] puts [fold {{a b} {return $a,$b}} x $1to5]</lang>
- Output:
15 120 x,1,2,3,4,5
Note that these particular operations would more conventionally be written as: <lang tcl>puts [::tcl::mathop::+ {*}$1to5] puts [::tcl::mathop::* {*}$1to5] puts x,[join $1to5 ,]</lang> But those are not general catamorphisms.
Wortel
You can reduce an array with the !/
operator.
<lang wortel>!/ ^+ [1 2 3] ; returns 6</lang>
If you want to reduce with an initial value, you'll need the @fold
operator.
<lang wortel>@fold ^+ 1 [1 2 3] ; returns 7</lang>
zkl
Most sequence objects in zkl have a reduce method. <lang zkl>T("foo","bar").reduce(fcn(p,n){p+n}) //--> "foobar" "123four5".reduce(fcn(p,c){p+(c.matches("[0-9]") and c or 0)}, 0) //-->11 File("foo.zkl").reduce('+(1).fpM("0-"),0) //->5 (lines in file)</lang>