2013-08-14 4 views
0

나는 학습 목적으로이 아주 작은 요구 사항을 가지고있다. 스칼라 모나드 ?? 또는 기능 구성

우리가
은 "1.1"장
입니다
이 장
"의 제목입니다"이것은 테스트입니다 ""이것은 34 테스트를 1.1 "

다음 문자열이 있다고 가정 34 "는 페이지 번호입니다.

전체 결과는"구문 분석 된 "행이 괜찮은지 여부에 대한 약간의 표시를 제공해야합니다.
현재 "잘 형성 된"라인에서만 작동합니다 (이것은 의도적입니다).

지금까지 나는이 문제를 해결하는 2 가지 방법 ...
1) 메신저이 때문에 내 질문을 잘 수행하지 완전히 확실하지만 모나드 접근()

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을 생성하는 코드에 대한 더 높은 차수의 함수입니다.하지만 지금은 간단하게 유지하려고합니다. 중요한 것은 모나드에 관한 것입니다.

마지막으로 이것이 주요 논리입니다.

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

유 기능 광산 유형에 "래핑"NOT 반환형()를 제외하고 동일하다 볼 수 있고, 또한이 방법을 가지고

,369을 다음과 같이

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 접근 방식"과 동일합니다.

마지막으로 질문은 다음과 같습니다.
"모나드 접근"은 실제로 모나드입니까?
작문 접근 논리가 더 쉽습니다.이 특별한 경우 모나드 접근법은 과도한 것처럼 보일 수 있지만 학습 목적으로 사용하는 것을 기억하십시오.

두 가지 접근 방식에서 논리 흐름이 쉽게 발생한다는 것을 알았습니다.

두 경우 모두 필요하면 문자열 행을 구문 분석하기 위해 단계를 추가하거나 제거하기가 쉽습니다.

나는이 코드가 매우 유사하고 개선의 여지가 있지만 지금은 간단하고 어쩌면 미래에 나는 일을 바꾸지 않을 것이라고 알고있다.

제안을 환영합니다.

답변

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

과 같을 것이다, 이것은 취향에 빠지고 당신이 원하는인지 부하는 자신에 배치합니다.

+0

splitline 메서드에 대한 제안에 감사드립니다. 내 미래 리팩토링에 적합하다는 것을 알 수 있습니다. 정규 표현식을 사용할 계획입니다.인지로드 부분에 동의합니다. – yan