gpt4 book ai didi

javascript - 好的,*这是* monadic 吗?

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:50:49 26 4
gpt4 key购买 nike

我在面向文档的前面放置了一个安全层,我需要一种合理抽象的方式让应用程序定义哪些新文档以及对现有文档的哪些更新对特定用户来说是合法的。

具体问题是-- 文档被定义(至少在传输过程中)为 JSON 对象,因此规则可能是分层的,因此规则引擎必须递归地工作。例如,Employee 对象可能有一个名为 Compensation 的子对象,该子对象有一个名为 PayPeriod 的字段,该字段必须是“每周”、“双周”或“每月”之一。-- 它运行 Node.js 并且一些规则需要从输入中读取(例如,从数据库中读取更多用户数据),因此它必须以连续方式运行。

所以我想到的是:每个规则都是一个函数,它接受当前值、建议的新值,以及使用要使用的值调用的回调。该值可以是两个输入之一,也可以是规则计算的第三个值。这是一条规则:

var nonEmpty = function(proposedValue, existingValue, callback) {
callback( (proposedValue.length > 0) ? proposedValue : existingValue);
};

此规则只允许您使用非零长度值设置或替换此字段。当然,这只对字符串值有意义(暂时忽略列表,所以我们需要一个规则来强制执行字符串):

var isString = function(proposedValue, existingValue, callback) {
callback( ( typeof(proposedValue) === 'string') ? proposedValue : existingValue);
};

事实上,这似乎是一种常见的问题,所以我写了一个规则生成器:

var ofType = function(typeName) {
return function(proposedValue, existingValue, callback) {
callback( ( typeof(proposedValue) === typeName) ? proposedValue : existingValue);
};
};

var isString = ofType('string')

但我需要一种将规则串在一起的方法:

var and = function(f1, f2) {
return function(proposedValue, existingValue, callback) {
f1(proposedValue, existingValue,
function(newProposedValue) {
f2(newProposedValue, existingValue, callback);
});
};
};

var nonEmptyString = and(isString, nonEmpty);

因此管理员更新员工记录的规则可能是:

limitedObject({
lastName : nonEmptyString,
firstName : nonEmptyString,
compensation : limitedObject({
payPeriod : oneOf('weekly', 'biweekly', 'monthly'),
pay : numeric
}
})

limitedObject(如 ofType)是一个规则生成函数,它只允许其参数中指定的字段并将给定规则应用于这些字段的值字段。

所以我写了所有这些,它就像一个魅力。我所有的错误结果都是单元测试中的错误!好吧,几乎所有的人。不管怎样,如果你已经读到这里,这是我的问题:

我一直在狂热地研究单子(monad),我的阅读启发了我以这种方式解决问题。但是,这真的是单子(monad)的吗?

(可能的答案:"is"、“否,但这没关系,因为单子(monad)并不是解决这个问题的真正正确方法”,以及“否,这是需要改变的地方”。也欢迎第四种可能性。)

最佳答案

不,这似乎不是单子(monad)的。您所定义的似乎是规则 组合器 的迷你 DSL,其中您有简单的规则,例如 ofType(typeName) 以及将规则组合成更大规则的方法,例如 和(规则 1,规则 2)

为了拥有一个 monad,您需要一些上下文概念,您可以在其中放置任何值。您还需要进行以下操作:

  1. wrap(x) 函数,用于将任何 值放入某些默认上下文。
  2. 函数 map(f, m) 用于应用函数 f 来转换 m 中的值而不改变上下文。<
  3. 函数 flatten(mm) 用于将上下文的两层展平为一层。

这些操作必须满足某些“显而易见”的规律:

  1. 在外部添加一层上下文并折叠,让您回到开始时的状态。

    flatten(wrap(m)) == m
  2. 在内部添加一层上下文并折叠,让您回到开始时的状态。

    flatten(map(wrap, m)) == m
  3. 如果您有一个包含三层上下文的值,那么先折叠两个内层还是两个外层都没有关系。

    flatten(flatten(mmm)) == flatten(map(flatten, mmm))

也可以根据上面的 wrap 和另一个操作 bind 来定义一个 monad,但是这等同于上面的,因为你可以定义 根据 mapflatten 进行绑定(bind),反之亦然。

function bind(f, m) { return flatten(map(f, m)); }

# or

function map(f, m) { return bind(function(x) { return wrap(f(x)); }, m); }
function flatten(mm) { return bind(function(x) { return x; }, mm); }

目前尚不清楚上下文的概念是什么,以及如何将任何值转化为规则。因此,如何扁平化两层规则的问题就更没有意义了。

我认为 monad 在这里不是合适的抽象。

但是很容易看出您的 确实形成了 monoid始终成功规则(如下所示)作为身份元素。

function anything(proposedValue, existingValue, callback) {
callback(proposedValue);
}

关于javascript - 好的,*这是* monadic 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7211790/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com