2011-10-16 7 views
3

최근에 하스켈을 배우기 시작했고 하스켈에서 파이썬으로 인터뷰 한 내용을 다시 작성하려고합니다. 낙타의 문자열을 "("myVariableName "->"my_variable_name ") 분리 된 밑줄로 변환하려고합니다. 또한 첫 번째 문자가 대문자 인 경우 오류가 발생합니다. 나는 그것은 내가 이상한 방법으로 이것에 대해 갈거야, 나는이 구현하는 더 나은 방법에 대한 조언을 싶지만 꽤 가능성이 높습니다 실현초보자 하스켈 문제 (... 발생하지 않는 인스턴스)

import qualified Data.Char as Char 

translate_java :: String -> String 
translate_java xs = translate_helper $ enumerate xs 
    where 
     translate_helper [] = [] 
     translate_helper ((a, num):xs) 
      | num == 1 and Char.isUpper a = error "cannot start with upper" 
      | Char.isUpper a    = '_' : Char.toLower a : translate_helper xs 
      | otherwise     = a : translate_helper xs 


enumerate :: (Num b, Enum b) => [a] -> [(a,b)] 
enumerate xs = zip xs [1..] 

하지만, 내가 좋아하는 것 : 여기

내가 가진 무엇 이것을 컴파일하기 위해서도.

Prelude> :r 
[1 of 1] Compiling Main    (translate.hs, interpreted) 

translate.hs:4:20: 
    No instance for (Num 
         (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t)) 
     arising from a use of `translate_helper' at translate.hs:4:20-35 
    Possible fix: 
     add an instance declaration for 
     (Num (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t)) 
    In the first argument of `($)', namely `translate_helper' 
    In the expression: translate_helper $ enumerate xs 
    In the definition of `translate_java': 
     translate_java xs 
         = translate_helper $ enumerate xs 
         where 
          translate_helper [] = [] 
          translate_helper ((a, num) : xs) 
               | num == 1 and Char.isUpper a 
               = error "cannot start with upper 
" 
               | Char.isUpper a 
               = '_' : Char.toLower a : transla 
te_helper xs 
               | otherwise = a : translate_help 
er xs 
Failed, modules loaded: none. 

것은 여기에 무슨 일이 일어나고 있는지의 모든 설명이 좋은 것 : 여기 지금지고있어 오류입니다. 나는 정말로 "(Num (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))"가 어디에서 오는지 이해하지 못합니다. translate_helper에 대한 타입 선언은 [(a, b)] -> [a]와 같을 것이라고 생각합니다.

답변

4

문제점이있다 :

| num == 1 and Char.isUpper a = ... 

and

는 중위 연산자 아니다

and :: [Bool] -> Bool 

그래서는 "기능"1에 세 개의 인수를 적용하기로 1 and Char.isUpper a 해석된다 오히려 기능입니다. 대신 &&을 사용하십시오.

오류 메시지는 숫자가 해석되는 방식에서 비롯됩니다. 숫자, 예를 들어 1은 실제로 다형성을가집니다. 그것이 가져 오는 특정 유형은 필요한 유형에 따라 다릅니다. 그렇기 때문에 이라고 말할 수 있으며 x이 정수 이건 두 번 이건 상관없이 작동합니다. 그래서 컴파일러는 1의 형식이 3 가지 인수 함수 여야한다고 추론하고 1을 해당 유형으로 변환 할 수있는 숫자 형식을 찾으려고 시도했습니다 (당연히 실패했습니다).

+0

빠른 응답을 보내 주셔서 감사합니다. 나는 그 기능을 영원히 바라 보았으며, 나는 그 사실을 결코 파악하지 못했을 것이라고 생각합니다. 다형성이 1 인 것에 대한 좋은 설명. – cgag

5

and&&으로 대체해야합니다. 첫 번째는 부울 값의 목록을 받고 그 중 하나와 모두를 계산하는 함수 (접두사)입니다. 두 번째 것은 진정한 논리적 사고입니다. 오류 메시지는 약간 혼란 스럽다. 이런 이상한 에러 메시지가 나올 때마다 보통 코드에 타입 시그니처로 주석을 달기 시작합니다. 그렇다면 컴파일러는 무엇이 잘못되었는지에 대한 자세한 설명을 줄 수 있습니다.

+0

형식 서명을 추가하려고했으나 상황이 악화되지 않을만큼 자신감이 부족하다는 것을 알고 있습니다. translate_helper의 형식 시그니처에 대해 무엇을 넣으시겠습니까? 나는 [(a, b)] -> [a]를 가졌지 만, char가 typeclass가 아니기 때문에 a가 Char임을 지정하는 방법을 확신하지 못했습니다. – cgag

+1

@cgag :'a'가 항상'Char'라고 가정한다면,'a (char, b)] -> [Char]'와 같이 타입 시그니처에서'a'를'Char'로 바꿀 수 있습니다. – hammar

5

다른 사람들은 and 대신 (&&)을 사용해야한다고 언급 했으므로 나는 다른 질문에 답할 것입니다 : 아니오, 나는 이상한 방식으로이 문제에 대해 생각하지 않습니다.

... 나는 그것이 일 수 있다고 생각합니까? 우아한!

translate_java (x:xs) | isUpper x = error "cannot start with an upper" 
translate_java xs = concatMap translate xs where 
    translate x = ['_' | isUpper x] ++ [toLower x] 

여기에가는 몇 가지 흥미로운 것들을있다 :

  1. 특별한 경우가 바로 확인됩니다. 이 작업을 반복 할 때까지 기다리지 마십시오!
  2. concatMap 함수는 많은 경우에 매우 편리합니다. map 다음에 concat이옵니다.이 글을 직접 작성했다면 아마도 xs >>= translate을 대신 사용할 것입니다.
  3. ['_' | isUpper x]은 목록 이해력입니다. 이는 술어가 보유하는지 여부에 따라 0 또는 1 개의 요소가 포함 된 목록을 작성하는 귀여운 관용구입니다.

이외의 코드는 매우 자명합니다.

3

여기 내 해결책이 있습니다. Daniel Wagner가 concatMap과 목록 이해를 사용하여 준 답처럼 대단한 것은 아니지만 초보자에게는 이해하기가 쉽습니다.

conv :: String -> String 
conv [] = [] 
conv [email protected](x:xs) = if Char.isUpper x 
       then error "First character cannot be uppercase" 
       else change s 

change :: String -> String 
change [] = [] 
change (x:xs) = if Char.isUpper x 
       then '_' : Char.toLower x : change xs 
       else x : change xs 

은 기능 전환은 정말 첫 번째 문자가 대문자가 아니어야합니다 당신의 기준을 확인하고, 그렇지 않은 경우는 작업을 수행하는 기능 변화에 문자열을 넘겨. 모든 문자를 하나씩 거쳐 목록을 작성하고 문자가 대문자 인 경우 밑줄을 추가하고 문자의 소문자 버전을 추가합니다. 그렇지 않으면 문자가 이미 소문자이면 그대로 추가합니다.