Hi, it's ITO Friday again. I still have an improved patch for the reduce function (http://en.wikipedia.org/wiki/Reduce_%28higher-order_function%29) lying around (see attachment). It adds two versions of the function:
1) One that takes an initial value. integer sum = list::reduce(integer x, integer y, 0, [ 1, 2, 3 ], { return x + y; }); integer product = list::reduce(integer x, integer y, 1, [ 1, 2, 3 ], { return x * y; }) 2) One were the initial value is the value of the first list entry. Here the list must of course have at least one entry. integer min = list::reduce(integer x, integer y, [ 1, 2, 3 ], { return x < y ? x : y; }); integer max = list::reduce(integer x, integer y, [ 1, 2, 3 ], { return x > y ? x : y; }); The behaviour is now analogous to Python's reduce so it shouldn't be completely screwed. The patch contains no binary incompatibility to libycp or the bytecode. Please comment. ciao Arvin
Index: YCPBuiltinList.cc =================================================================== --- YCPBuiltinList.cc (revision 48433) +++ YCPBuiltinList.cc (working copy) @@ -1083,6 +1083,121 @@ static YCPValue +l_reduce1 (const YCPSymbol &x, const YCPSymbol &y, const YCPList &list, const YCPCode &expr) +{ + /** + * @builtin list::reduce + * @id reduce_1 + * @short Reduces a list to a single value. + * @param flex1 x + * @param flex1 y + * @param list<flex1> list + * @param block<flex1> expr + * @return flex1 + * + * TODO + */ + + if (list.isNull()) + { + return YCPNull(); + } + + if (list->size() < 1) + { + ycp2error("Bad list %s for 'reduce'", list->toString().c_str()); + return YCPNull(); + } + + SymbolEntryPtr xs = x->asEntry()->entry(); + SymbolEntryPtr ys = y->asEntry()->entry(); + + YCPValue ret = list->value(0); + + for (int i = 1; i < list->size(); i++) + { + xs->setValue(ret); + ys->setValue(list->value(i)); + + YCPValue tmp = expr->evaluate(); + if (tmp.isNull()) + { + ycp2error("Bad 'reduce' expression %s", expr->toString().c_str()); + continue; + } + if (tmp->isVoid()) + { + ycp2error("The expression for 'reduce' returned 'nil'"); + continue; + } + if (tmp->isBreak()) + { + break; + } + + ret = tmp; + } + + return ret; +} + + +static YCPValue +l_reduce2 (const YCPSymbol &x, const YCPSymbol &y, const YCPValue &initial, const YCPList &list, const YCPCode &expr) +{ + /** + * @builtin list::reduce + * @id reduce_2 + * @short Reduces a list to a single value. + * @param flex1 x + * @param flex2 y + * @param flex1 value + * @param list<flex2> list + * @param block<flex1> expr + * @return flex1 + * + * TODO + */ + + if (list.isNull()) + { + return YCPNull(); + } + + SymbolEntryPtr xs = x->asEntry()->entry(); + SymbolEntryPtr ys = y->asEntry()->entry(); + + YCPValue ret = initial; + + for (int i = 0; i < list->size(); i++) + { + xs->setValue(ret); + ys->setValue(list->value(i)); + + YCPValue tmp = expr->evaluate(); + if (tmp.isNull()) + { + ycp2error("Bad 'reduce' expression %s", expr->toString().c_str()); + continue; + } + if (tmp->isVoid()) + { + ycp2error("The expression for 'reduce' returned 'nil'"); + continue; + } + if (tmp->isBreak()) + { + break; + } + + ret = tmp; + } + + return ret; +} + + +static YCPValue l_tolist (const YCPValue &v) { /** @@ -1143,5 +1258,14 @@ { 0 } }; + // must be static, registerDeclarations saves a pointer to it! + static declaration_t declarations_ns[] = { + { "list", "", NULL, DECL_NAMESPACE }, + { "reduce", "flex1 (variable <flex1>, variable <flex1>, const list <flex1>, const block <flex1>)", (void *)l_reduce1, DECL_LOOP|DECL_SYMBOL|DECL_FLEX }, + { "reduce", "flex1 (variable <flex1>, variable <flex2>, const flex1, const list <flex2>, const block <flex1>)", (void *)l_reduce2, DECL_LOOP|DECL_SYMBOL|DECL_FLEX }, + { 0 } + }; + static_declarations.registerDeclarations ("YCPBuiltinList", declarations); + static_declarations.registerDeclarations ("YCPBuiltinList", declarations_ns); }