diff --git a/docs/dev-guide/graphql/graphql-type.md b/docs/dev-guide/graphql/graphql-type.md index b2802d2a2..3faa94103 100644 --- a/docs/dev-guide/graphql/graphql-type.md +++ b/docs/dev-guide/graphql/graphql-type.md @@ -19,7 +19,7 @@ GraphQL缺省只有Float、Int、String、Boolean、ID这几种基本类型。No ```java -static class ResultBean { +class ResultBean { List list; @GraphQLReturn(bizObjName = "MyObject") diff --git a/docs/theory/thinking-in-functional-programming.md b/docs/theory/thinking-in-functional-programming.md index 4a90135b3..11801973a 100644 --- a/docs/theory/thinking-in-functional-programming.md +++ b/docs/theory/thinking-in-functional-programming.md @@ -6,3 +6,126 @@ ## 三. 从函数到函子 +# 实用主义观点下的函数式编程思想 + +## 一. 引言 +### 1.1 函数式编程的兴起 +- 函数式编程的历史背景 +- 为什么函数式编程在现代开发中越来越重要 +- 实用主义视角下的函数式编程:从理论到实践 + +### 1.2 文章目标 +- 探讨函数式编程的核心思想 +- 从实用主义角度分析函数式编程的优势与挑战 +- 提供实际案例,帮助读者理解如何将函数式编程应用于现实问题 + +--- + +## 二. 函数式编程的核心思想 +### 2.1 纯函数与不可变性 +- 纯函数的定义与特性 +- 不可变数据结构的优势 +- 纯函数在实践中的应用场景 + +### 2.2 高阶函数与函数组合 +- 高阶函数的概念与作用 +- 函数组合:将小函数组合成复杂逻辑 +- 实际案例:使用高阶函数简化代码 + +### 2.3 声明式编程 +- 声明式编程与命令式编程的对比 +- 如何通过声明式编程提高代码可读性 +- 实际案例:使用声明式风格处理数据 + +--- + +## 三. 函数式编程的核心工具 +### 3.1 函子(Functor) +- 函子的定义与基本操作(`fmap`) +- 函子的实际应用:处理容器中的值 +- 实际案例:使用函子处理可选值(`Maybe`) + +### 3.2 单子(Monad) +- 单子的定义与核心操作(`return` 和 `bind`) +- 单子的实际意义:处理副作用与计算顺序 +- 实际案例:使用单子处理异步操作(`Promise`) + +### 3.3 应用函子(Applicative Functor) +- 应用函子的定义与操作 +- 应用函子与函子、单子的关系 +- 实际案例:使用应用函子处理多个上下文中的函数 + +--- + +## 四. 函数式编程的实用价值 +### 4.1 代码的可维护性 +- 纯函数与不可变性如何提高代码的可维护性 +- 实际案例:重构命令式代码为函数式风格 + +### 4.2 并行与并发编程 +- 函数式编程如何简化并行与并发编程 +- 实际案例:使用函数式编程处理多线程任务 + +### 4.3 测试与调试 +- 纯函数如何简化单元测试 +- 实际案例:为函数式代码编写测试 + +### 4.4 函数式编程的局限性 +- 函数式编程的学习曲线 +- 性能问题与优化策略 +- 何时选择函数式编程,何时选择其他范式 + +--- + +## 五. 函数式编程在现代开发中的应用 +### 5.1 前端开发 +- 函数式编程在前端框架中的应用(如React、Redux) +- 实际案例:使用函数式编程构建UI组件 + +### 5.2 后端开发 +- 函数式编程在服务器端开发中的应用(如Node.js、Scala) +- 实际案例:使用函数式编程处理API请求 + +### 5.3 数据处理与机器学习 +- 函数式编程在数据处理中的应用(如MapReduce) +- 实际案例:使用函数式编程处理大规模数据集 + +--- + +## 六. 函数式编程的未来 +### 6.1 函数式编程与新兴技术 +- 函数式编程在区块链、物联网等领域的应用 +- 函数式编程与人工智能的结合 + +### 6.2 函数式编程的普及与教育 +- 如何降低函数式编程的学习门槛 +- 函数式编程在计算机教育中的角色 + +### 6.3 函数式编程的社区与生态 +- 函数式编程语言的发展趋势(如Haskell、Elm、Clojure) +- 函数式编程工具与库的生态系统 + +--- + +## 七. 结论 +### 7.1 函数式编程的核心价值 +- 从实用主义角度总结函数式编程的优势 +- 函数式编程如何改变开发者的思维方式 + +### 7.2 如何开始学习函数式编程 +- 推荐学习资源与路径 +- 实践建议:从小项目开始,逐步深入 + +### 7.3 函数式编程的未来展望 +- 函数式编程在软件开发中的长期影响 +- 开发者如何拥抱函数式编程的思想 + +--- + +## 参考文献 +- 相关书籍、论文与在线资源 +- 函数式编程语言与工具的官方文档 + +--- + +这个大纲从实用主义的角度出发,系统地探讨了函数式编程的核心思想、工具、应用场景以及未来发展方向。通过理论与实际案例的结合,旨在帮助读者深入理解函数式编程的价值,并将其应用于实际开发中。 diff --git a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/RuleConstants.java b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/RuleConstants.java index 27ba2454c..b6eefdbc4 100644 --- a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/RuleConstants.java +++ b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/RuleConstants.java @@ -45,4 +45,6 @@ public interface RuleConstants { String ENUM_RULE_TYPE_MATX = "MATX"; String FIELD_LOG_MESSAGES = "logMessages"; + + String WEIGHT_NAME_POSTFIX = "__weight"; } diff --git a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/RuleErrors.java b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/RuleErrors.java index 2ed6d0726..82ca5de51 100644 --- a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/RuleErrors.java +++ b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/RuleErrors.java @@ -18,6 +18,9 @@ public interface RuleErrors { String ARG_DISPLAY_NAME = "displayName"; + String ARG_RULE_NAME = "ruleName"; + String ARG_OUTPUT_NAME = "outputName"; + ErrorCode ERR_RULE_WORKBOOK_NO_RULE_SHEET = define("nop.err.rule.workbook-no-rule-sheet", "工作簿中没有名称为Rule的Sheet"); @@ -64,4 +67,7 @@ public interface RuleErrors { ErrorCode ERR_RULE_INPUT_VAR_NOT_ALLOW_EMPTY = define("nop.err.rule.input-var-not-allow-empty", "输入变量不允许为空:name={varName},displayName={displayName}", ARG_VAR_NAME, ARG_DISPLAY_NAME); + + ErrorCode ERR_RULE_AGGREGATE_WEIGHT_SIZE_NOT_MATCH = + define("nop.err.rule.aggregate-weight-size-not-match", "权重列表长度与输出列表长度不一致", ARG_RULE_NAME, ARG_OUTPUT_NAME); } diff --git a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/execute/NormalizeOutputExecutableRule.java b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/execute/NormalizeOutputExecutableRule.java index 96021b2bb..4a05fa792 100644 --- a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/execute/NormalizeOutputExecutableRule.java +++ b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/execute/NormalizeOutputExecutableRule.java @@ -7,7 +7,10 @@ */ package io.nop.rule.core.execute; +import io.nop.api.core.convert.ConvertHelper; +import io.nop.api.core.exceptions.NopException; import io.nop.commons.util.CollectionHelper; +import io.nop.commons.util.MathHelper; import io.nop.core.lang.eval.IEvalAction; import io.nop.core.lang.utils.Underscore; import io.nop.rule.core.IExecutableRule; @@ -15,8 +18,14 @@ import io.nop.rule.core.model.RuleAggregateMethod; import io.nop.rule.core.model.RuleOutputDefineModel; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import static io.nop.rule.api.RuleApiErrors.ARG_RULE_NAME; +import static io.nop.rule.core.RuleErrors.ARG_OUTPUT_NAME; +import static io.nop.rule.core.RuleErrors.ERR_RULE_AGGREGATE_WEIGHT_SIZE_NOT_MATCH; + public class NormalizeOutputExecutableRule implements IExecutableRule { private final IExecutableRule rule; private final List outputs; @@ -52,6 +61,26 @@ private void aggOutput(RuleOutputDefineModel output, IRuleRuntime ruleRt) { return; } + boolean useWeight = output.isUseWeight(); + List weights = null; + if (useWeight) { + weights = getWeights(ruleRt, output.getWeightName()); + if (weights.isEmpty()) { + useWeight = false; + } else { + if (weights.size() != list.size()) { + throw new NopException(ERR_RULE_AGGREGATE_WEIGHT_SIZE_NOT_MATCH) + .param(ARG_RULE_NAME, ruleRt.getRuleName()).param(ARG_OUTPUT_NAME, name); + } + + List withWeights = new ArrayList<>(list.size()); + for (int i = 0; i < list.size(); i++) { + withWeights.add(MathHelper.multiply(list.get(i), weights.get(i))); + } + list = withWeights; + } + } + switch (aggMethod) { case min: { Object value = Underscore.min(list); @@ -73,6 +102,16 @@ private void aggOutput(RuleOutputDefineModel output, IRuleRuntime ruleRt) { ruleRt.setOutput(name, value); break; } + case weighted_avg: { + Object value = Underscore.sum(list); + Number sumWeight = list.size(); + if (useWeight) { + sumWeight = Underscore.sum(weights); + } + value = MathHelper.divide(value, sumWeight); + ruleRt.setOutput(name, value); + break; + } case list: { ruleRt.setOutput(name, list); break; @@ -87,6 +126,19 @@ private void aggOutput(RuleOutputDefineModel output, IRuleRuntime ruleRt) { } } + private List getWeights(IRuleRuntime ruleRt, String name) { + List list = ruleRt.getOutputList(name); + if (list == null || list.isEmpty()) + return Collections.emptyList(); + List weights = new ArrayList<>(list.size()); + for (Object obj : list) { + weights.add(ConvertHelper.toPrimitiveDouble(obj, 1.0, + err -> new NopException(err) + .param(ARG_RULE_NAME, ruleRt.getRuleName()).param(ARG_OUTPUT_NAME, name))); + } + return weights; + } + private Object getDefaultValue(RuleOutputDefineModel output, IRuleRuntime ruleRt) { IEvalAction defaultExpr = output.getDefaultExpr(); if (defaultExpr == null) { diff --git a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/model/RuleAggregateMethod.java b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/model/RuleAggregateMethod.java index e525d829d..c17656b59 100644 --- a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/model/RuleAggregateMethod.java +++ b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/model/RuleAggregateMethod.java @@ -25,6 +25,9 @@ public enum RuleAggregateMethod { @Label("取平均值") avg, + @Label("按权重取平均值") + weighted_avg, + @Label("取第一个值") first, diff --git a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/model/RuleOutputDefineModel.java b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/model/RuleOutputDefineModel.java index c606f3d45..ac403f141 100644 --- a/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/model/RuleOutputDefineModel.java +++ b/nop-rule/nop-rule-core/src/main/java/io/nop/rule/core/model/RuleOutputDefineModel.java @@ -7,10 +7,15 @@ */ package io.nop.rule.core.model; +import io.nop.rule.core.RuleConstants; import io.nop.rule.core.model._gen._RuleOutputDefineModel; -public class RuleOutputDefineModel extends _RuleOutputDefineModel{ - public RuleOutputDefineModel(){ +public class RuleOutputDefineModel extends _RuleOutputDefineModel { + public RuleOutputDefineModel() { } + + public String getWeightName() { + return getName() + RuleConstants.WEIGHT_NAME_POSTFIX; + } }