编程语言
首页 > 编程语言> > javascript – 好的,是*这个* monadic?

javascript – 好的,是*这个* monadic?

作者:互联网

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

特别的问题是
– 文档被定义(至少在传输中)作为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);

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

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

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

所以我写了这一切,它就像一个魅力.我的所有错误都证明是单元测试中的错误!好吧,几乎所有人.无论如何,如果你已经读到这一点,这是我的问题:

我一直热情地研究monad,我的阅读激励我以这种方式解决问题.但是,这真的是monadic吗?

(可能的答案:“是的”,“不,但这没关系,因为monad不是解决这个问题的正确方法”,“不,这就是需要改变的东西”.第四种可能性也值得欢迎.)

解决方法:

不,这似乎不是一元的.您所定义的似乎是规则组合器的迷你DSL,其中您有简单的规则,如ofType(typeName)以及将规则组合成更大规则的方式,如和(rule1,rule2).

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

>函数换行(x),用于将任何值放入某个默认上下文中.
>函数映射(f,m),用于应用函数f来转换m中的值而不改变上下文.
>用于展平两层上下文的函数展平(mm).

这些操作必须满足某些“明显”的法律:

>在外部添加一层上下文并折叠可以让您回头开始.

flatten(wrap(m)) == m

>在内部添加一层上下文并折叠可以让您回到开始时的内容.

flatten(map(wrap, m)) == m

>如果您有一个具有三层上下文的值,那么首先是折叠两个内层还是两个外层并不重要.

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

也可以根据上面的换行和另一个操作绑定来定义monad,但是这等同于上面的,因为你可以用map和flatten来定义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,monads
来源: https://codeday.me/bug/20190626/1294492.html