我对学习目的的要求非常小。
假设我们有以下字符串
“1.1这是一个测试34”
其中
“1.1”是章
“这是一个考验”是章的标题
“34”是页码
总体结果应该给我一些指示“解析”线是否正常
现在它只用于“形成良好”的线(这是故意的)。
到目前为止,我有两种解决方法... ...
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的“out”值并创建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方法似乎有点矫枉过正,但请记住这是出于学习目的。
我发现在这两种方法中逻辑流程都很容易推理。
如果两种情况都需要,可以轻松添加甚至删除步骤以解析字符串行。
我知道这段代码非常相似,并且有改进的余地,但现在我保持简单,也许将来我会把事情搞清楚。
欢迎提出建议。
答案 0 :(得分:0)
首先,您的代码中不需要var
。其次,由于您正在使用字符串的substring
函数,因此您只需要一个部分函数来获取子字符串的偏移量。这将是重构时开始的好地方,如果格式改变,将允许各种功能分割线。
这看起来像
def splitline(method:String)(symbol:String)(s:String) = method match {
case "substring" => val symb = Integer.parseInt(symbol) ;(s.substring(0,symb),s.substring(symb))
}
val getTitle = splitline("substring")("3") _
在构图或单一代码方面,这取决于偏好和认知 加载你希望放在自己身上。