双眼皮功能型图案
让玩具类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() )
}
该类提供了String和自然数之间的映射,每次查询新的String时都会延迟扩展该映射。
然后我可以编写一个方法,可以将字符串序列转换为整数序列,从而在遍历期间更新映射。我得到的第一个实现是使用 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
实现不是很满意。问题是我折叠了两个不同的值。是否有函数式编程模式来简化实现?
Let the toy-class Counter
such as:
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() )
}
This class provides a mapping between a String and a natural number, the mapping is extended lazily each time a new String is queried.
I can then write a method which can convert a Seq of Strings in a Seq of Ints, updating the mapping during traversal. The first implementation I got is with 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 )
}
This works as intended:
val ss = Seq( "foo", "bar", "baz", "foo", "baz" )
val is = toInt( ss, Counter() )._1
//is == List(0, 1, 2, 0, 2)
But I am not very satisfied about toInt
implementation. The problem is that I am folding on two different values. Is there a functional programming pattern to simplify the implementation ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您正在寻找的模式是
State
monad:那里的类型注释很不幸,也许可以通过某种方式消除它。无论如何,这是一个运行过程:
The pattern you're looking for is the
State
monad:The type annotation there is unfortunate, and maybe it can be eliminated somehow. Anyway, here's a run of it:
您可以通过进行更多模式匹配来使折叠看起来更好一点:
然后,如果您有 管道运算符
|>
在某处定义,并且您对/:
别名感到满意>向左折叠,你 就可以使其变得紧凑且可读。一旦您熟悉了语法,
You can make the fold you've got look quite a bit nicer by doing more pattern matching:
And then if you have the pipe operator
|>
defined somewhere, and you're comfortable with the/:
alias forfoldLeft
, you can make thatwhich is, once you're familiar with the syntax, compact and readable.
我认为 state monad 就是您正在寻找的。
I think the state monad is what you're looking for.
折叠两个值并没有什么问题。它可以稍微改进:
或者,如果你愿意,
或者甚至,
Nothing wrong with folding on two values. It can be slightly improved:
Or, if you prefer,
Or even,