Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.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 将多个转换链接到状态Monad_Scala_Scalaz_Scala Cats_State Monad_Scalaz7 - Fatal编程技术网

Scala 将多个转换链接到状态Monad

Scala 将多个转换链接到状态Monad,scala,scalaz,scala-cats,state-monad,scalaz7,Scala,Scalaz,Scala Cats,State Monad,Scalaz7,我开始使用state monad来清理我的代码。我已经让它解决了我的问题,我处理了一个名为CDR的事务,并相应地修改了状态。 使用此函数执行状态更新,对于单个事务来说,它工作得非常好 def addTraffic(cdr: CDR): Network => Network = ... 以下是一个例子: scala> val processed: (CDR) => State[Network, Long] = cdr => | for { | m <

我开始使用state monad来清理我的代码。我已经让它解决了我的问题,我处理了一个名为CDR的事务,并相应地修改了状态。 使用此函数执行状态更新,对于单个事务来说,它工作得非常好

def addTraffic(cdr: CDR): Network => Network = ...
以下是一个例子:

scala> val processed: (CDR) => State[Network, Long] = cdr =>
 |   for {
 |     m <- init
 |     _ <- modify(Network.addTraffic(cdr))
 |     p <- get
 |   } yield p.count
processed: CDR => scalaz.State[Network,Long] = $$Lambda$4372/1833836780@1258d5c0

scala> val r = processed(("122","celda 1", 3))
r: scalaz.State[Network,Long] = scalaz.IndexedStateT$$anon$13@4cc4bdde

scala> r.run(Network.empty)
res56: scalaz.Id.Id[(Network, Long)] = (Network(Map(122 -> (1,0.0)),Map(celda 1 -> (1,0.0)),Map(1 -> Map(1 -> 3)),1,true),1)
我尝试对此进行调整失败,但我无法使它们类型的签名匹配,因为我的状态函数需要cdr(事务)输入

谢谢

TL;DR
您可以在
CDR
s的集合(例如
List
)上的
traverse
类型类中使用带有以下签名的函数:
CDR=>State[Network,Long]
。结果将是一个
状态[网络,列表[长]]
。或者,如果您不关心那里的
列表[Long]
,您可以使用
遍历
,它将返回
状态[Network,Unit]
。最后,如果您想“聚合”结果
T
,并且
T
形成
Monoid
,您可以使用
Foldable
中的
foldMap
,它将返回
状态[Network,T]
,其中
T
是链中所有
T
的组合(例如折叠)结果

代码示例
现在提供更多详细信息和代码示例。我将使用Scalaz而不是Scalaz来回答这个问题,因为我从未使用过后者,但概念是相同的,如果您仍然有问题,我将找出正确的语法

假设我们要处理以下数据类型和导入:

import cats.implicits._
import cats.data.State

case class Position(x : Int = 0, y : Int = 0)

sealed trait Move extends Product
case object Up extends Move
case object Down extends Move
case object Left extends Move
case object Right extends Move
很明显,
位置
表示二维平面中的一个点,
移动
可以上下左右移动该点

现在,让我们创建一个方法,让我们能够看到在给定时间我们所处的位置:

def whereAmI : State[Position, String] = State.inspect{ s => s.toString }
以及一种改变我们位置的方法,给定一个
移动

def move(m : Move) : State[Position, String] = State{ s => 
  m match {
    case Up => (s.copy(y = s.y + 1), "Up!")
    case Down => (s.copy(y = s.y - 1), "Down!")
    case Left => (s.copy(x = s.x - 1), "Left!")
    case Right => (s.copy(x = s.x + 1), "Right!")
  }
}
请注意,这将返回一个
字符串
,移动名称后跟感叹号。这只是为了模拟从
Move
到其他对象的类型更改,并显示如何聚合结果。更多关于这一点在一点

现在让我们尝试一下我们的方法:

val positions : State[Position, List[String]] = for{
  pos1 <- whereAmI 
  _ <- move(Up)
  _ <- move(Right)
  _ <- move(Up)
  pos2 <- whereAmI
  _ <- move(Left)
  _ <- move(Left)
  pos3 <- whereAmI
} yield List(pos1,pos2,pos3)
(您可以忽略那里的
.value
,这是一个怪癖,因为
状态[s,a]
实际上只是
状态[Eval,s,a]
的别名)

如您所见,这与您预期的一样,您可以创建不同的“蓝图”(例如,状态修改序列),一旦提供初始状态,就会应用这些蓝图

现在,为了真正回答您的问题,假设我们有一个
列表[Move]
,我们希望将它们依次应用到初始状态,并得到结果:我们使用
遍历

或者,如果您根本不需要
A
(在您的案例中是
列表
),您可以使用
遍历
,而不是
遍历
,结果类型为:

val result_ : State[Position, List[String]] = moves.traverse_(move)
result_.run(Position()).value // (Position(-1,-1),Unit)
最后,如果您的
A
状态中键入[S,A]
形成
Monoid
,那么您也可以使用
foldMap
from
Foldable
组合(例如折叠)所有
A
的计算结果。一个简单的例子(可能没用,因为这只会连接所有
String
s)如下:

val result : State[Position,String] = moves.foldMap(move)
result.run(Position()).value // (Position(-1,-1),Down!Down!Left!Up!)
最后一种方法对您是否有用,实际上取决于您拥有的
A
,以及将其组合起来是否合理


这应该是您在场景中所需要的全部

只是为了检查我是否正确理解了您的问题:您想知道如何将此模式依次应用于(比如)5个CDR吗?e、 g.给定一个初始状态,您希望将第一个CDR应用于该状态,将第二个CDR应用于上一步的结果状态,依此类推……正确吗?是的,但对于迭代器上的CDR,我可以手动应用它们,就像手动一个接一个地应用一样,但我的目标是能够针对任何大小的块运行此操作。感谢您的回复,这让我走上了正确的道路。我不得不做一些小的调整;首先定义了一个别名,因为State有太多的“漏洞”:键入NetworkState[A]=State[Network,A],然后我创建了我的CDR列表,以提供val miscdrs:list[CDR]=(new-CDRFromRandom(5).buffer map{x=>x.getCDR})。toList val结果:NetworkState[list[Long]=CDRs.traverse[NetworkState,Long](processCDR)我也必须给编译器一些帮助。。。val result=cdrs.traverse[NetworkState,Long](processCDR)result.run(Network.empty)我现在还有两个问题:第一,是否可以使用迭代器来保持它的惰性?第二,我对列表不太感兴趣,因为它可能会变得非常大(数亿个元素,我可以去掉它并保留最后一个值吗?感谢您回答第一个问题:您不需要
迭代器来保持它的惰性。
State[S,A]
StateT[Eval,S,A]的别名
,而
Eval
所做的恰恰是:它使它变得懒惰。如果你不需要整个
列表
,那么你可以使用
foldMap
from
Foldable
而不是
traverse
。这个概念很相似,但给出了一个
List[Move]
和一个函数
Move=>State[Position,String]
,它将返回
状态[位置,字符串]
,其中最后的
字符串是
字符串的
幺半群的
合并
操作的结果,在这种情况下(这是串联,但您可以将其更改为案例中需要的).最后,如果这个回答有用,请给出答案。
val moves = List(Down, Down, Left, Up)
val result : State[Position, List[String]] = moves.traverse(move)
result.run(Position()).value // (Position(-1,-1),List(Down!, Down!, Left!, Up!))
val result_ : State[Position, List[String]] = moves.traverse_(move)
result_.run(Position()).value // (Position(-1,-1),Unit)
val result : State[Position,String] = moves.foldMap(move)
result.run(Position()).value // (Position(-1,-1),Down!Down!Left!Up!)