scala中纯函数与副作用的混合
我有一个简单的api方法:scala中纯函数与副作用的混合,scala,functional-programming,Scala,Functional Programming,我有一个简单的api方法: def addWishToBoard(wish: Wish, boardId: BoardId, userId: UserId): Option[Board] 如果boardId和userId匹配,它会向board添加愿望 电路板简单地存储在一个列表中: private var boards = List.empty[Board] 我在这里使用var来模拟副作用 实施代码: def addWishToBoard(wish: Wish, boardId: Board
def addWishToBoard(wish: Wish, boardId: BoardId, userId: UserId): Option[Board]
如果boardId
和userId
匹配,它会向board添加愿望
电路板简单地存储在一个列表中:
private var boards = List.empty[Board]
我在这里使用var来模拟副作用
实施代码:
def addWishToBoard(wish: Wish, boardId: BoardId, userId: UserId): Option[Board] = {
val board = find(boardId)
.filter(_.ownerId == userId)
.map(board => board.copy(wishes = wish :: board.wishes.toList))
board.foreach(b => boards = b :: boards)
board
}
是否有功能性的方法来实现这种副作用,而不使用val作为电路板?如何组合返回单元的副作用和返回选项[Board]
的纯函数
scala> case class Board()
defined class Board
scala> val ob = Option.empty[Board]
ob: Option[Board] = None
然后定义以下内容
scala> implicit class AnyOps[A](val any: A) extends AnyVal {
| def tap(effect: A => Unit): A = { effect(any); any }
| }
defined class AnyOps
然后使用它
scala> ob.tap(println)
None
res9: Option[Board] = None
从功能编程的角度来看,副作用应该通过IO
;比如:
scala> import scalaz._; import Scalaz._; import effect._
import scalaz._
import Scalaz._
import effect._
scala> OptionT(ob.point[IO]) >>! { b =>
| IO.putStrLn(b.toString).liftM[OptionT]
| }
res12: scalaz.OptionT[scalaz.effect.IO,Board] =
OptionT(scalaz.effect.IO$$anon$7@3fd8d23d)
这里的返回类型(当然)封装了效果。但是,我强烈怀疑您的程序需要大量的重新编写才能正常运行(即在任何地方都没有var
s),因此tap
解决方案可能就是您想要的您可以接受一个函数,如果我们设法生产一块电路板,该函数将被调用
def addWishToBoard(wish: Wish, boardId: BoardId, userId: UserId)(sideEffect: Board => Board = identity): Option[Board] =
find(boardId)
.filter(_.ownerId == userId)
.map(board => sideEffect(board.copy(wishes = wish :: board.wishes.toList)))
您也可以使用选项的fold
def addWishToBoard(wish: Wish, boardId: BoardId, userId: UserId): Option[Board] =
find(boardId)
.filter(_.ownerId == userId)
.map(board =>board.copy(wishes = wish :: board.wishes.toList))
.fold(None){v =>
sideEffect(v)
Some(v)
}
现在还不清楚你想在这里实现什么。。。
在不使用val
的情况下,有很多方法可以编写此文件。例如:
boards
.find(boardId)
.filter(_.ownerId == userId)
.map(board => board.copy(wishes = wish :: board.wishes.toList))
.map(b => boards = b :: boards; b)
或者,也许
def addBoard(b: Board) = {
boards = b :: boards
b
}
boards
.find(boardId)
.filter(_.ownerId == userId)
.map(board => board.copy(wishes = wish :: board.wishes.toList))
.map(addBoard)
(顺便说一句,您使用此功能不断地向列表中添加同一块板的“版本”,而不删除以前的副本-这似乎没有多大意义) boards.foreach(board=>boards=board::boards)你是说board.foreach(b=>boards=b::boards)?@Ivan是的,我的意思是board.foreach(b=>boards=b::boards)
我将更新以避免混淆读者首先我在boardId列表中找到board,然后我检查当前的用户id是否与所有者id匹配(is user是该董事会的所有者)。如果是,我通过向其添加愿望来更改该董事会,然后我用新的董事会列表更新董事会列表。演示副作用操作是人为的,在本例中为变量赋值。我知道您正在这样做:)我只是说,如果您向同一董事会添加两个愿望,你的名单上会有三个版本的董事会,分别包含0、1和两个愿望。对于没有评论的反对票,你有点困惑,为什么?