문제

나는 그것이 기능 프로그래밍에 더 가까워지는 데 도움이되기를 희망하면서 Haskell을 배우고 있습니다. 이전에는 주로 C, Java 및 D와 같은 C와 같은 구문이있는 언어를 사용했습니다.

코딩 스타일에 대해 약간의 질문이 있습니다. if/else 제어 블록이 사용했습니다 Wikibooks에 대한 튜토리얼. 코드는 다음과 같습니다.

doGuessing num = do
   putStrLn "Enter your guess:"
   guess <- getLine
   if (read guess) < num
     then do putStrLn "Too low!"
             doGuessing num
     else if (read guess) > num
            then do putStrLn "Too high!"
                    doGuessing num
            else do putStrLn "You Win!"

이 코딩 스타일이 C와 같은 언어로 권장 스타일을 완전히 위반하기 때문에 혼란스러워합니다. if, else if, 그리고 else 같은 열에서.

나는 그것이 Haskell에서 작동하지 않는다는 것을 알고 있습니다. else 같은 열에서 if.

그러나 다음 스타일은 어떻습니까? 나는 그것이 위의 것보다 훨씬 명확하다고 생각합니다. 그러나 위의 내용은 Wikibooks와 공식 Haskell 웹 사이트에서 "온라인으로 제공되는 최고의 튜토리얼"으로 표시된 또 다른 Haskell 튜토리얼에서 사용하기 때문에이 코딩 스타일이 Haskell 프로그램의 컨벤션인지 확실하지 않습니다.

doGuessing num = do
    putStrLn "Enter your guess:"
    guess <- getLine
    if (read guess) < num then
        do 
            putStrLn "Too low!"
            doGuessing num
        else if (read guess) > num then do 
            putStrLn "Too high!"
            doGuessing num
        else do 
            putStrLn "You Win!"

그래서 어떤 코딩 스타일이 더 자주 사용되는지 궁금합니다. 아니면이 코드에 대한 또 다른 코딩 스타일이 있습니까?

도움이 되었습니까?

해결책

Haskell 스타일은 기능적이며 필수적이지 않습니다! "이렇게하는 것"보다는 기능을 결합하고 설명하는 것에 대해 생각합니다. 무엇 귀하의 프로그램은 방법이 아니라 할 것입니다.

게임에서 귀하의 프로그램은 사용자에게 추측을 요청합니다. 올바른 추측은 승자입니다. 그렇지 않으면 사용자가 다시 시도합니다. 게임은 사용자가 올바르게 추측 할 때까지 계속되므로 다음을 작성합니다.

main = untilM (isCorrect 42) (read `liftM` getLine)

이것은 동작을 반복적으로 실행하는 빗질기를 사용합니다 (getLine 입력 라인을 가져옵니다 read 이 경우 해당 문자열을 정수로 변환하고 결과를 확인합니다.

untilM :: Monad m => (a -> m Bool) -> m a -> m ()
untilM p a = do
  x <- a
  done <- p x
  if done
    then return ()
    else untilM p a

술어 (부분적으로 적용됩니다 main) 올바른 값에 대한 추측을 확인하고 그에 따라 응답합니다.

isCorrect :: Int -> Int -> IO Bool
isCorrect num guess =
  case compare num guess of
    EQ -> putStrLn "You Win!"  >> return True
    LT -> putStrLn "Too high!" >> return False
    GT -> putStrLn "Too low!"  >> return False

플레이어가 올바르게 추측 할 때까지 실행되는 조치는

read `liftM` getLine

간단하게 유지하고 두 기능을 구성하지 않겠습니까?

*Main> :type read . getLine

<interactive>:1:7:
    Couldn't match expected type `a -> String'
           against inferred type `IO String'
    In the second argument of `(.)', namely `getLine'
    In the expression: read . getLine

유형 getLine ~이다 IO String, 하지만 read 순수한 것을 원합니다 String.

함수 liftM Monad는 순수한 기능을 취하고 모나드로“들어 올립니다”. 표현의 유형은 우리에게 그것이하는 일에 대해 많은 것을 알려줍니다.

*Main> :type read `liftM` getLine
read `liftM` getLine :: (Read a) => IO a

실행할 때 우리에게 전환 된 값을 돌려주는 I/O 동작입니다. read, an Int 우리의 경우. 기억하십시오 readLine 생산하는 I/O 동작입니다 String 가치가 있으므로 생각할 수 있습니다 liftM 우리가 신청할 수있게합니다 read "내부" IO 모나드.

샘플 게임 :

1
Too low!
100
Too high!
42
You Win!

다른 팁

"case"-구성을 사용할 수 있습니다.

doGuessing num = do
    putStrLn "Enter your guess:"
    guess <- getLine
    case (read guess) of
        g | g < num -> do 
            putStrLn "Too low!"
            doGuessing num
        g | g > num -> do 
            putStrLn "Too high!"
            doGuessing num
        otherwise -> do 
            putStrLn "You Win!"

Mattiast의 사례 진술 (편집하지만 업장이 부족한)에 대한 약간의 개선은 비교 함수를 사용하는 것입니다.

doGuessing num = do
   putStrLn "Enter your guess:"
   guess <- getLine
   case (read guess) `compare` num of
     LT -> do putStrLn "Too low!"
              doGuessing num
     GT -> do putStrLn "Too high!"
              doGuessing num
     EQ -> putStrLn "You Win!"

나는이 Haskell 질문을 정말 좋아하며 다른 사람들이 더 많은 것을 게시하도록 권장합니다. 종종 당신은있는 것 같습니다 갖다 당신이 생각하는 것을 표현하는 더 나은 방법이 되려면, Haskell은 처음에는 너무 외국이되어 아무것도 떠오를 것입니다.

Haskell Journyman에 대한 보너스 질문 : 도둑의 유형은 무엇입니까?

Haskell이 해석하는 방식 if ... then ... else ~ 이내에 do 블록은 Haskell의 구문 전체와 매우 관련이 있습니다.

그러나 많은 사람들이 약간 다른 구문을 선호하며 then 그리고 else 해당하는 것과 동일한 들여 쓰기 수준에서 나타나려면 if. 따라서 GHC는 옵트 인 언어 확장 기능이 있습니다. DoAndIfThenElse, 이 구문을 허용합니다.

그만큼 DoAndIfThenElse 확장은 Haskell 사양의 최신 개정에서 핵심 언어의 일부로 만들어집니다. Haskell 2010.

'do'블록 내부에서 '그때'와 'else'를 들여 보내야한다는 사실은 많은 사람들에 의해 버그로 간주됩니다. 아마도 Haskell 사양의 다음 버전 인 Haskell '(Haskell Prime)에서 고정 될 것입니다.

곱슬 버팀대와 함께 명시 적 그룹을 사용할 수도 있습니다. 레이아웃 섹션을 참조하십시오 http://www.haskell.org/tutorial/patterns.html

나는 그것을 추천하지 않을 것입니다. 나는 몇 가지 특별한 경우 외에도 명시 적 그룹을 사용하는 사람을 본 적이 없습니다. 나는 보통 표준 전주곡 코드 스타일의 예를 위해.

나는 Wikibooks의 예와 같은 코딩 스타일을 사용합니다. 물론 C 지침을 따르지 않지만 Haskell은 C가 아니며 특히 익숙해지면 상당히 읽을 수 있습니다. 또한 Cormen과 같은 많은 교과서에 사용되는 알고리즘 스타일을 따라 패턴 화되었습니다.

당신은 Haskell에 대한 다양한 들여 쓰기 스타일을 볼 수 있습니다. 그들 중 대부분은 어떤 스타일이든 정확하게 들여 쓰기로 설정된 편집자 없이는 유지하기가 매우 어렵습니다.

당신이 표시하는 스타일은 편집자의 훨씬 간단하고 덜 까다 롭습니다. 나는 당신이 그것을 고수해야한다고 생각합니다. 내가 볼 수있는 유일한 불일치는 당신이 그 당시/else 이후에 다른 DOS를 넣는 동안 첫 번째 행동을 자체 라인에 넣는 것입니다.

Haskell에서 코드에 대해 생각하는 방법에 대한 다른 조언에 귀를 기울이지 만 계약 스타일을 고수하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top