我试图了解如何使用 scalazState
执行复杂的有状态计算。这是问题所在:
给定 a
List[Int]
个潜在除数和 aList[Int]
个数字,找到一个List[(Int, Int)
] 匹配对 (divisor, number),其中一个除数最多可以匹配一个数字。
作为测试:
def findMatches(divs: List[Int], nums: List[Int]): List[(Int, Int)]
并使用以下输入:
findMatches( List(2, 3, 4), List(1, 6, 7, 8, 9) )
我们最多可以得到 3 场比赛。如果我们规定匹配必须按照它们遍历列表 lr 的顺序进行,那么匹配必须是:
List( (2, 6) , (3, 9) , (4, 8) )
所以需要通过以下两个测试:
assert(findMatches(List(2, 3, 4), List(1, 6, 7, 8, 9)) == List((2, 6), (3, 9), (4, 8)))
assert(findMatches(List(2, 3, 4), List(1, 6, 7, 8, 11)) == List((2, 6), (4, 8)))
这是一个必要的解决方案:
scala> def findMatches(divs: List[Int], nums: List[Int]): List[(Int, Int)] = {
| var matches = List.empty[(Int, Int)]
| var remaining = nums
| divs foreach { div =>
| remaining find (_ % div == 0) foreach { n =>
| remaining = remaining filterNot (_ == n)
| matches = matches ::: List(div -> n)
| }
| }
| matches
| }
findMatches: (divs: List[Int], nums: List[Int])List[(Int, Int)]
请注意,我必须更新remaining
以及 accumulating的状态matches
。这听起来像是 scalaz traverse 的工作!
我无用的工作让我走到了这一步:
scala> def findMatches(divs: List[Int], nums: List[Int]): List[(Int, Int)] = {
| divs.traverse[({type l[a] = State[List[Int], a]})#l, Int]( div =>
| state { (rem: List[Int]) => rem.find(_ % div == 0).map(n => rem.filterNot(_ == n) -> List(div -> n)).getOrElse(rem -> List.empty[(Int, Int)]) }
| ) ~> nums
| }
<console>:15: error: type mismatch;
found : List[(Int, Int)]
required: Int
state { (rem: List[Int]) => rem.find(_ % div == 0).map(n => rem.filterNot(_ == n) -> List(div -> n)).getOrElse(rem -> List.empty[(Int, Int)]) }
^