【问题标题】:Function that will execute function depending on value. Functional programming将根据值执行函数的函数。函数式编程
【发布时间】:2017-10-01 18:46:31
【问题描述】:

我有两个函数,它们的执行取决于 if 语句。例如:

if(value) {
    doA()
} else {
    doB()
}

如何编写将获取结果并决定是否执行每个函数的函数或对象。我想收到这样的东西:

exists(result).doA()
nothing(result).doB()

我想在 JavaScrit 中学习一些函数式编程,所以我很感激任何可以让我在 JavaScript 中学习 FP 的资源。

【问题讨论】:

  • 对不起,我不明白。您似乎已经有了工作代码,对吧(在第一个 sn-p 中)? “我想收到这样的东西”是什么意思?第二个 sn-p 应该是一个测试套件,还是一种编写与第一个 sn-p 相同的东西的方法?
  • 你要(value ? doA : doB)()吗?
  • 是的,类似于 (value ? doA : doB)()
  • 我不认为你会通过将这个微不足道的运算符包装在一个函数中来获得任何东西

标签: javascript functional-programming


【解决方案1】:

续传风格

这是一种使用continuation passing style 的方法。您会注意到main 的实现与您的原始编码相差不远—— 一旦你完成了这一点,如果你还没有了解monads,你现在知道最好的一个(cont)^_^

// cont :: a -> (a -> b) -> b
const cont = x =>
  k => k (x)
  
// when :: (a -> boolean, a -> b, a -> b) -> a -> (a -> b) -> b
const when = (f,l,r) => x =>
  f (x) ? cont (l (x)) : cont (r (x))

// isOdd :: number -> boolean  
const isOdd = x =>
  x & 1 === 1
  
// doA :: number -> number    
const doA = x =>
  x + 1

// doB :: number -> number
const doB = x =>
  x * x

// main :: number -> void
const main = x =>
  cont (x) (when (isOdd, doA, doB)) (console.log)
  
main (3) // IO: 4,  doA (3) === 3 + 1
main (4) // IO: 16, doB (4) === 4 * 4

数据构造函数

这是另一种方法,使用简单的数据构造函数 LeftRight 来表示 Fork sum type - 这会产生一种 data-directed 样式,其中 main 的控制由输入类型决定

// type Fork a = Left a | Right a

// Left a :: { fork :: (a -> b, _) -> b }
const Left = x =>
  ({ type: Left, fork: (f,_) => f (x) })

// Right a :: { fork :: (_, a -> b) -> b }  
const Right = x =>
  ({ type: Right, fork: (_,f) => f (x) })

// doA :: number -> number    
const doA = x =>
  x + 1

// doB :: number -> number
const doB = x =>
  x * x

// main :: Fork a -> a
const main = f =>
  // fork applies the left function (doA) to a Left
  // fork applies the right function (doB) to a Right
  f.fork (doA, doB)
  
console.log (main (Left (3)))  // => 4, doA (3) === 3 + 1
console.log (main (Right (3))) // => 9, doB (3) === 3 * 3

【讨论】:

    【解决方案2】:

    你可以这样写,例如:

    function exists(value) {
        return function (func) {
            if (value !== undefined) {
                return func(value);
            }
            return null;
        }
    }
    
    function nothing(value) {
        return function (func) {
            if (value === undefined) {
                return func();
            }
            return null;
        }
    }
    
    function doA(value) {
        console.log('doing A', value);
    }
    
    function doB() {
        console.log('doing B');
    }
    
    const foo = 'fool';
    const bar = undefined;
    
    exists(foo)(doA);
    nothing(bar)(doB);
    

    exists 函数获取一个值并返回另一个函数。返回的函数获取另一个函数作为参数,如果定义了传递的值。

    我在上面的示例中使用了“老派”匿名函数以使其更易于理解。使用 ES6 箭头函数,您可以更简洁地编写 existsnothing 函数,如下所示:

    function exists(value) {
        return func => value !== undefined ? func(value) : null;
    }
    
    function nothing(value) {
        return func => value === undefined ? func(value) : null;
    }
    

    “函数式编程的乐趣”真正开始于您意识到可以通过将公共代码放在另一个函数中来重构这两个函数,然后使用该函数创建这两个函数,如下所示:

    function executeWithCondition(predicate) {
        return value => func => predicate(value) ? func(value) : null;
    }
    
    const exists = executeWithCondition(value => value !== undefined);
    const nothing = executeWithCondition(value => value === undefined);
    

    这种技术称为currying

    这些函数的用法还是一样的:

    exists(foo)(doA);
    nothing(bar)(doB);
    

    这是完整的可运行代码示例:

    function executeWithCondition(predicate) {
        return value => func => predicate(value) ? func(value) : null;
    }
    
    const exists = executeWithCondition(value => value !== undefined);
    const nothing = executeWithCondition(value => value === undefined);
    
    function doA(value) {
        console.log('doing A', value);
    }
    
    function doB() {
        console.log('doing B');
    }
    
    const foo = 'fool';
    const bar = undefined;
    
    exists(foo)(doA);
    nothing(bar)(doB);

    【讨论】:

    • 谢谢。这正是我想要的:)
    • 很好地展示了使用一些函数式技术来发明一个界面——由此产生的existsnothing 大多是无用的,但是展示如何从无到有还是很酷的!
    【解决方案3】:

    一种方法是使用设置为函数的值来定义对象的属性

    const o = {
      exists: function(value) {
        return value ? this.doA() : this.doB()
      },
      doA: function(value) {
        console.log("A")
      },
      doB: function(value) {
        console.log("B")
      }
    }
    
    o.exists(void 0);

    【讨论】:

      猜你喜欢
      • 2015-10-03
      • 2020-02-02
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-26
      • 1970-01-01
      • 2013-01-13
      相关资源
      最近更新 更多