斯卡拉单子?或函数组合 [英] scala monad?? or function composition

查看:32
本文介绍了斯卡拉单子?或函数组合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了学习目的,我有这个非常小的要求.

i have this very small requirement for learning purposes.

假设我们有以下字符串

"1.1 这是一个测试 34"
哪里
1.1"是章节
这是一个测试"是本章的标题
34"是页码

"1.1 This is a test 34"
where
"1.1" is the chapter
"This is a test" is the title of the chapter
"34" is the page number

总体结果应该给我一些指示解析"行是否正常.
目前它仅适用于格式良好"的线条(这是故意的).

The overall result should give me some indication whether or not "parsed" line is ok.
Right now its only working for "well formed" lines (this is on purpose).

到目前为止,我有两种方法可以解决这个问题...
1)Monad 方法(虽然我不完全确定这是正确的,因此我的问题)

So far i have 2 ways of solving this...
1) Monad approach (though im not entirely sure this is done right, therefore my question)

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)
 }
}

而且我还有以下功能可以从我的字符串"行中获取文本

and i also have following functions for getting text out of my "string" line

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 的东西.

I can think of trying to use a higher order function for code that gets values "out" of Tuple2 and creation of Attempt1 stuff, but right now i want to keep things simple, the important thing for me is the monad stuff.

最后这是主要逻辑.

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 类型包装")之外,函数是相同的,而且我也有这个方法

as u can see functions are the same except on the return type (not "wrapped" by a Mine type), and i also have this method

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方法"相同.

returnes values are the same as the "Monad approach".

所以最后的问题是:
Monad 方法"真的是 Monad 吗??
我发现组合方法逻辑更容易,对于这种特殊情况,Monad 方法可能看起来有点矫枉过正,但请记住,这是出于学习目的.

So finally the questions would be:
Is "Monad approach" really a Monad??
I find compositional approach logic easier, and for this particular case Monad approach might seem overkill but remember this is for learning purposes.

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

I find that in both approaches logic flow is easy to reason.

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

If needed in both cases is easy to add or even remove a step in order to parse a string line.

我知道这段代码非常相似并且有改进的余地,但现在我保持简单,也许将来我会将常见的事情排除在外.

I know this code is so similar and has room for improvement but right now im keeping it simple and maybe in the future i will factor commong things out.

欢迎提出建议.

推荐答案

首先,您的代码中不需要 var .其次,由于您使用的是字符串的 substring 函数,因此您只需要一个获取子字符串偏移量的部分函数.这将是重构时的一个好起点,并且允许在格式发生变化时使用不同的功能来分割行.

First off there is no need for the vars in your code. Second, since you are using substring function of a string, all you need is one partial function which takes the offsets of the sub-strings. This would be a good place to start when refactoring and would allow varied functionality for how you split the lines should the format change.

这看起来像

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

在组合或一元代码方面,这取决于偏好和认知您希望自己承受的负荷.

In terms of composition or monadic code, this falls on preference and the cognitive load you wish to place on yourself.

这篇关于斯卡拉单子?或函数组合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆