Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
scala中纯函数与副作用的混合_Scala_Functional Programming - Fatal编程技术网

scala中纯函数与副作用的混合

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

我有一个简单的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: 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和两个愿望。对于没有评论的反对票,你有点困惑,为什么?