Functional programming 在函数式编程中,是否有一种干净的方法可以对某些数据执行许多操作,而不必显式地将数据传递给每个函数?

Functional programming 在函数式编程中,是否有一种干净的方法可以对某些数据执行许多操作,而不必显式地将数据传递给每个函数?,functional-programming,monads,Functional Programming,Monads,假设我有几个函数可以对某些数据执行业务逻辑: function addEmployees(data, numberOfNewEmployees){ // Business logic... data.employeeCount += numberOfNewEmployees; return data; } function withdrawFunds(data, withdrawAmount){ // Business logic... data.che

假设我有几个函数可以对某些数据执行业务逻辑:

function addEmployees(data, numberOfNewEmployees){
    // Business logic...
    data.employeeCount += numberOfNewEmployees;
    return data;
}

function withdrawFunds(data, withdrawAmount){
    // Business logic...
    data.checkingAccount -= withdrawAmount;
    return data;
}

function completeAnOrder(data){
    // Business logic...
    data.pendingOrders -- 1;
    return data;
}
现在,要对一些数据执行一些操作,我有如下内容(假设数据是通过副本传递的):

我很好奇,在函数式编程世界中,是否有一种优雅的方法可以实现这一点:

const data = {
    employeeCount: 5,
    checkingAccount: 5000,
    pendingOrders: 2
}

let biz = createBiz(data);

const newData = biz.addEmployees(2)
    .withdrawFunds(2000)
    .completeAnOrder()
    .toValue();
在JavaScript中,我知道对象可以返回
this
,这就是JQuery方法链接的工作方式

但是,在函数世界中有没有一种优雅的方法来做类似的事情呢?我意识到我可能是想把OOP的想法强加给FP


有解决这个问题的单子吗?为特定的业务逻辑创建自己的自定义monad有意义吗?

这将在很大程度上取决于语言和该语言可用的工具

在中,这类任务通常使用宏来解决。在这种情况下,这将使用“线程”宏完成

假设我有你的功能:

;所有这些函数都返回修改后的数据
(定义添加员工[新员工的数据编号]
...)
(defn提取资金[数据提取金额]
...)
(定义完成订单[数据]
...)
由于“this”(数据
)是第一个参数,因此我可以使用
->
将参数自动“线程化”到每个调用:

(定义数据{:员工计数5,
:支票帐户5000,
:待决订单(2})
(->数据
(添加employees 2);其结果作为提取资金的第一个参数获得通过
(2000年提取资金);然后传递结果以完成订单。。。
(完成订单);同上
(价值)
宏扩展后,基本上变成:

(进行估价(完成订单(提取资金(添加员工数据2)2000)))

但是,如果您将来使用合成,那么使用
->

将更容易阅读和更改。在Haskell中,如果操作是在结构上操作并返回新结构的纯函数,而不是I/O操作,则可以通过几种不同的方式编写,例如:
toValue。完成订单。2000年。addEmployees 2$data
。(也可以使用
从左到右写入)

不过,您更可能看到该示例变成了有状态代码,并对外部数据库产生了副作用。在Haskell中,这将使用应用程序或单子的抽象,但大多数其他函数式语言不会对数学形式主义如此严格。应用程序版本允许您编写类似于
runValue$completeOrder 2000 addEmployees 2数据的内容。或者您可以将其写为
do

Facebook给出了一些数据库代码是如何做到这一点的。命令式代码:

NumCommonFriends(x, y) = Length(Intersect(FriendsOf(x), FriendsOf(y)))
具有应用程序版本

numCommonFriends x y =
  length <$> (intersect <$> friendsOf x <*> friendsOf y)
numCommonFriends x y=
长度(相交交友x交友y)
它可以用一些语法上的糖分写成

numCommonFriends x y = do
  fx <- friendsOf x
  fy <- friendsOf y
  return (length (intersect fx fy))
numCommonFriends x y=do

外汇链与
这件事无关
。您只需要返回一个可以调用方法的对象(任何对象)。当然,在函数式编程中,您更愿意返回一个新对象,而不是改变输入,但这是一个正交问题。
numCommonFriends x y = do
  fx <- friendsOf x
  fy <- friendsOf y
  return (length (intersect fx fy))