2013-08-26 2 views
3

어떻게 하스켈에서 이와 유사한 함수를 결합 할 수 있습니까?하스켈에서의 결합 함수

getGroup [] acc = reverse acc 
getGroup ((Letter x):letfs) acc = getGroup letfs ((Letter x):acc) 
getGroup ((Group x):letfs) acc = getGroup letfs ((Group (makeList x)):acc) 
getGroup ((Star x):letfs) acc = getGroup letfs ((Star (makeList x)):acc) 
getGroup ((Plus x):letfs) acc = getGroup letfs ((Plus (makeList x)):acc) 
getGroup ((Ques x):letfs) acc = getGroup letfs ((Ques (makeList x)):acc) 

Letter, Group, Star, Plus 및 Ques는 모두 데이터 형식 정의의 일부입니다.

data MyData a 
     = Operand a 
     | Letter a 
     | Star [RegEx a] 
     | Plus [RegEx a] 
     | Ques [RegEx a] 
     | Pipe [RegEx a] [RegEx a] 
     | Group [RegEx a] 
     deriving Show 

유사점 때문에 이러한 기능을 작성하는 더 좋은 방법이 있는지 궁금합니다. 대부분 Group, Star, Plus 및 Ques의 기능을 동일하게 결합하기를 원합니다. 그러나 모두를 결합하는 방법이 있으면 더 좋을 것입니다.

답변

4

Template Haskell을 사용하지 않고도 패턴 매칭의 반복을 없앨 수는 없습니다. 아마도 5 개의 다른 생성자만으로는 가치가 없습니다. 다른 반복을 많이 없애고 함수의 성능 특성을 향상시킬 수 있습니다. 훨씬 더 간결 할뿐만

getGroup = map go 
    where go (Letter x) = Letter x 
     go (Group x) = Group . makeList $ x 
     go (Star x) = Star . makeList $ x 
     go (Plus x) = Plus . makeList $ x 
     go (Ques x) = Ques . makeList $ x 

, 그것은 또한 하스켈 같은 게으른 언어로 공간 누수가 발생할 것이다 꼬리 재귀를 제거한다.

+0

죄송합니다 ... 나는 하스켈을 처음 사용합니다. 그래서 내 함수 문자 (예를 들어) 실제로 될 것이다 :'이동 ((문자 x) : 왼쪽) acc = getGroup 왼쪽 ((문자 x) : acc)'? – tasegula

+1

아니요, 축전지를 제거하십시오. 게으른 평가를 처리 할 때 테일 재귀는 나쁩니다. 공간 누수가 발생합니다.'map'과 같은 higher order 함수를 사용하는 것이 더 낫지 만, 명시 적 재귀를 사용하려면이 getGroup ((Letter x) : lefts) = Letter x : getGroup lefts'와 같아야합니다. –

+0

이 오류가 발생했습니다 :'get '에 대한 구문 분석 오류가 두 번째 시도에서 발생합니다 :'getGroup = map go 여기서 \t go ((Letter x) : 왼쪽) = 문자 x : getGroup lefts go ((별표 x) : 왼쪽) = (별표 메이크업 $ x) : getGroup lefts go ((Plus x) : 왼쪽) = (더하기 makeList $ x) : getGroup lefts go ((Ques x) 왼쪽) = (QList. makeList $ x) : getGroup lefts \t \t go ((그룹. makeList $ x) : getGroup lefts') (그래서 첫 번째는 괜찮습니다.) – tasegula

4

데이터 유형 정의가 여러 가지 다른 경우의 분리 된 결합으로 정의 된 경우 필연적으로 해당 유형을 처리하는 함수에서 사례 분석의 큰 혼란이 발생합니다.

공통점 밖으로 감안하여 기본 유형을 단순화하는 것입니다 사례 분석을 줄이는 한 가지 방법이 정립에서

data MyData a = Val String a 
       | UnOp String [Regex a] 
       | BinOp String [Regex a] [Regex a] 

은, 각각의 경우는 다른 종류를 따로 말할 수있는 판별 자 필드가 각 경우의 여기에서는 "Operand", "Letter", "Star"등과 같은 이름을 사용한다고 가정하고 String을 사용했지만 Val 종류, UnOp 종류의 유효 discriminator에 대해 별도의 열거 유형을 정의 할 수도 있습니다.

이 경우 가장 중요한 것은 유형 안전입니다. 당신은 내가 준 것처럼 String 필드를 가지고 무의미한 것을 만들 수 있습니다. 이 문제를 해결하기위한 첫 번째 접근법은 스마트 생성자로 알려진 것을 사용하는 것입니다.; 이것들은보다 안전한 타입의 코어 데이터를 타입 세이프 (type-safe) 방식으로 만드는 특수한 타입의 매개 변수를 가진 함수입니다. 모듈에서 실제 MyData 생성자를 내 보내지 않는 한, 유형의 다른 사용자는 스마트 생성자를 통해서만 유용한 데이터를 생성 할 수 있습니다.

당신이 종류의 생성자 자체로부터 안전 공사의 더 보장을 원하는 경우에, 당신은 일반화 대수 데이터 형식 (GADTs)팬텀 유형의 개념을 설정 할 것이다. 이러한 기본 개념은 데이터 형식 정의의 = 왼쪽에있는 형식 변수와 오른쪽에 형식 변수를 더 유연하게 연결하는 것입니다. 그것들은 Haskell의 다소 새롭고 진보 된 기능이지만, 여러분은 표준 Haskell 데이터 유형을 확실하게 파악할 때까지 그것들에 뛰어 들지 않을 수 있습니다.