design-patterns - 双折功能图案

标签 design-patterns scala functional-programming

让玩具级Counter如:

class Counter private( val next: Int, val str2int: Map[String,Int] ) {
  def apply( str: String ): (Int,Counter)  = str2int get str match {
    case Some(i) => ( i, this )
    case None => ( next, new Counter( next+1, str2int + (str -> next) ) )
  }
}
object Counter {
  def apply() = new Counter( 0, Map() )
}

这个类提供了一个字符串和一个自然数之间的映射,每次查询一个新的字符串时映射都会被延迟扩展。

然后我可以编写一个方法,该方法可以在 Ints 序列中转换字符串序列,在遍历期间更新映射。我得到的第一个实现是 foldLeft :
def toInt( strs: Seq[String], counter: Counter ): ( Seq[Int], Counter ) =
  strs.foldLeft( (Seq[Int](), counter) ) { (result, str) =>
    val (i, nextCounter) = result._2( str )
    ( result._1 :+ i, nextCounter )
  }

这按预期工作:
val ss = Seq( "foo", "bar", "baz", "foo", "baz" )
val is = toInt( ss, Counter() )._1
            //is == List(0, 1, 2, 0, 2)

但是我对toInt不太满意执行。问题是我折叠了两个不同的值。是否有一种函数式编程模式来简化实现?

最佳答案

您正在寻找的模式是 State单子(monad):

import scalaz._
import Scalaz._

case class Counter(next: Int = 0, str2int: Map[String,Int] = Map()) {
  def apply( str: String ): (Counter, Int) = (str2int get str) fold (
    (this, _),
    (new Counter(next+1, str2int + (str -> next)), next)
  )}

type CounterState[A] = State[Counter, A]

def count(s: String): CounterState[Int] = state(_(s))

def toInt(strs: Seq[String]): CounterState[Seq[Int]] =
  strs.traverse[CounterState, Int](count)

那里的类​​型注释很不幸,也许它可以以某种方式消除。无论如何,这是一个运行它:
scala> val ss = Seq( "foo", "bar", "baz", "foo", "baz" )
ss: Seq[java.lang.String] = List(foo, bar, baz, foo, baz)

scala> val is = toInt(ss) ! Counter()
is: Seq[Int] = List(0, 1, 2, 0, 2)

关于design-patterns - 双折功能图案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7177134/

相关文章:

oop - 在应用程序中与 Elastic 通信的最佳实践

java - 这个看似过度设计的代码用于检查一个数字是另一个数字的倍数的原因是什么?

linux - 如何使 intellij Idea 使用 #! 正确突出显示 Scala 脚本? (shebang)

database - 如何在 Play 2.0 中为每个环境设置不同的数据库?

types - Coq:类型 (n) 中的 Prop 与 Set

design-patterns - 将依赖项注入(inject)单例类的一种不错的方法是什么?

wpf - MVVM - 与 WPF 命令绑定(bind)标准有关

scala - 如何从 Scala 中的派生类辅助构造函数调用辅助基类构造函数?

list - F#中 "merge"多个相同长度列表的惯用方法?

haskell - Erlang "single assignment"与 Haskell "immutable values"不同吗?