斯卡拉单子?或功能组成

时间:2013-08-14 21:05:20

标签: scala

我对学习目的的要求非常小。

假设我们有以下字符串

“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方法似乎有点矫枉过正,但请记住这是出于学习目的。

我发现在这两种方法中逻辑流程都很容易推理。

如果两种情况都需要,可以轻松添加甚至删除步骤以解析字符串行。

我知道这段代码非常相似,并且有改进的余地,但现在我保持简单,也许将来我会把事情搞清楚。

欢迎提出建议。

1 个答案:

答案 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") _

在构图或单一代码方面,这取决于偏好和认知 加载你希望放在自己身上。