出于学习目的,我有这个非常小的要求。
假设我们有以下字符串
“1.1 这是一个测试 34”
其中
“1.1”是章节
“这是一个测试”是章节的标题
“34”是页码
总体结果应该给我一些指示“解析”行是否可以。
现在它只适用于“格式良好”的行(这是故意的)。
到目前为止,我有 2 种方法来解决这个问题......
1)Monad 方法(虽然我不完全确定这是正确的,因此我的问题)
trait Mine[A] {
def get(): A
def map(f: A => A): Mine[A]
def flatMap(f: A => Mine[A]): Mine[A]
}
case class Attempt1[A, B](a: (A, B)) extends Mine[(A, B)] {
def get(): (A, B) = a
def map(f: ((A, B)) => (A, B)): Mine[(A, B)] = {
Attempt1(f(a._1, a._2))
}
def flatMap(f: ((A, B)) => Mine[(A, B)]): Mine[(A, B)] = {
f(a._1, a._2)
}
}
而且我还有以下功能可以从我的“字符串”行中获取文本
def getChapter2(t: (Result, String)): Mine[(Result, String)] = {
val result = t._1
val state = t._2
result.chapter = state.substring(0, 3)
var newState = state.substring(3)
Attempt1((result, newState))
}
def getTitle2(t: (Result, String)): Mine[(Result, String)] = {
val result = t._1
val state = t._2
result.title = state.substring(0, state.length() - 2)
var newState = state.substring(state.length() - 2)
Attempt1((result, newState))
}
def getPage2(t: (Result, String)): Mine[(Result, String)] = {
val result = t._1
val state = t._2
result.page = state
Attempt1((result, ""))
}
我可以考虑尝试对从 Tuple2 中“取出”值并创建 Attempt1 东西的代码使用更高阶的函数,但现在我想让事情保持简单,对我来说重要的是 monad 的东西。
最后,这是主要逻辑。
var line = "1.1 Some awesome book 12"
val result = new Result("", "", "")
val at1 = Attempt1((result, line))
val r = for (
o1 <- at1;
o2 <- getChapter2(o1);
o3 <- getTitle2(o2);
o4 <- getPage2(o3)
) yield (o4)
val res = r.get._1
println("chapter " + res.chapter) //1.1
println("title " + res.title) // Some awesome book
println("page " + res.page) // 12
2) 组合方法
def getChapter(t: (Result, String)): (Result, String) = {
val result = t._1
val state = t._2
result.chapter = state.substring(0, 3)
var newState = state.substring(3)
(result, newState)
}
def getTitle(t: (Result, String)): (Result, String) = {
val result = t._1
val state = t._2
result.title = state.substring(0, state.length() - 2)
var newState = state.substring(state.length() - 2)
(result, newState)
}
def getPage(t: (Result, String)): (Result, String) = {
val result = t._1
val state = t._2
result.page = state
(result, "")
}
正如你所看到的,除了返回类型(不是由 Mine 类型“包装”)之外,函数是相同的,而且我也有这个方法
def process(s: String, f: ((Result, String)) => (Result, String)): Result = {
val res = new Result("", "", "")
val t = f(res, s)
res
}
我的主要逻辑如下
var line = "1.1 Some awesome book 12"
var fx = getChapter _ andThen getTitle _ andThen getPage
var resx = process(line, fx)
printf("title: %s%nchapter: %s%npage: %s%n", resx.title, resx.chapter, resx.page)
返回值与“Monad 方法”相同。
所以最后的问题是:
“Monad 方法”真的是 Monad 吗?
我发现组合方法逻辑更容易,对于这种特殊情况,Monad 方法可能看起来有点矫枉过正,但请记住这是出于学习目的。
我发现在这两种方法中,逻辑流程都很容易推理。
如果在这两种情况下都需要,很容易添加甚至删除一个步骤以解析字符串行。
我知道这段代码非常相似并且有改进的余地,但现在我保持简单,也许将来我会考虑到共同点。
欢迎提出建议。