2017-02-26 1 views
0

getLine 함수를 사용하십시오.IO a -> a에서 함수를 작성 하시겠습니까?

은 내가이 IO 값에서 문자열을 추출하려면 어떻게 유형

getLine :: IO String 

있습니다. 더 일반적으로 어떻게 변환합니까? 이것에

IO a 

:

a 

이 불가능합니다. 내가 왜 이럴 수 없어?

+7

이렇게 할 수 있다면 처음에는 IO 유형을 사용하지 않아도됩니다. – sepp2k

+0

중복 될 수 : [* 어떻게하면 하스켈에서 IO 문자열을 구문 분석 할 수 있습니까?] (http://stackoverflow.com/q/11229854/2751851) 중복 대상). – duplode

답변

9

하스켈의 경우 IO에 "트랩 된"값을 사용하려면 IO 값을 사용하지 마십시오. 대신 수행 할 작업을 IO에 넣으십시오!

예를 들어, length Prelude의 기능을 사용하여 getLine :: IO String이 생성 할 문자 수를 확인한다고 가정합니다.

가, IO에 전문 때, 종류가 fmap라는 도우미 함수가 존재 : 그것은 IO에 갇혀 "순수"값에서 작동하는 기능을한다

fmap :: (a -> b) -> IO a -> IO b 

, 당신에게 기능을 제공합니다 IO에 갇혀있는 값과 함께 작동합니다. 이 코드

fmap length getLine :: IO Int 

콘솔에서 라인을 읽는 IO 행동을 나타낸다는 것을 의미하고 당신에게 길이를 제공합니다.

<$>은 더 단순하게 만들 수있는 fmap의 중위 동의어입니다. 이것은 위의 코드에 해당 : 이제

length <$> getLine 

, 당신은 IO -trapped 값을 반환IO -trapped 값 자체 수행 할 때때로 동작을 제어한다. 간단한 예 : 방금 읽은 문자열을 putStrLn :: String -> IO()을 사용하여 다시 쓸 수 있습니다.

이 경우 fmap은 충분하지 않습니다. IO으로 전문화 된 (>>=) 연산자는 IO a -> (a -> IO b) -> IO b 유형이어야합니다. 아웃 경우 :

getLine >>= putStrLn :: IO() 

체인에 IO 작업을 (>>=)를 사용하는 것은 필수적 순차적 맛이있다. 이보다 자연적인 방법으로 이와 같은 순차적 인 쓰기 작업을하는 데 도움이 "do-notation"라는 문법 설탕의 종류 :

do line <- getLine 
    putStrLn line 

공지 사항을 여기에 <-이 연산자 아니라고는하지만, 문법 설탕의 일부가 할 일에 의해 제공 표기법.

+0

이 일반적인 질문에 대한 간단한 설명! "대신에 수행하려는 작업을 IO에 넣어야합니다." – luqui

1

C를 알고 있다면 "gets에서 문자열을 가져올 수 있습니까?"라는 질문을 고려하십시오. IO String은 얻기가 힘들어하는 문자열이 아니며, 네트워크 또는 표준 입력에서와 같이 문자열을 반환 할 수있는 프로 시저입니다. 을 실행하려면 문자열을 가져 오는 절차를 실행하십시오. 당신 위는 다음 String 값을 얻을 수 있지만 원하는 값을 사용하도록 getLine 작업을 실행에

main = do 
    someString <- getLine 
    -- someString :: String 
    print someString 

: 순서대로 IO 작업을 실행하는

일반적인 방법은 do 표기법입니다.

2

do 블록에있는 사람이라면 <-으로 (비공식적으로/부정확하게) IO에서 값을 가져올 수 있습니다. 예를 들어

는 다음과 같은 기능을 getLine에서 선을 소요, 단지 문자열

main = do 
    line <- getLine 
    putStrLn (wrap line) 

wrap :: String -> String 
wrap line = "'" ++ line ++ "'" 

당신이 wrap으로이 컴파일하는 경우, 명령 줄 실행에 소요 순수 함수에 전달

echo "Hello" | wrap 

당신이 볼 수

'Hello' 
0

"일반적으로"그래서이 유형의 함수가 필요한 이유는 분명치 않으며이 경우에는 모든 점에서 차이가 있습니다.

가능한 것은 완전해야 함을 유의해야합니다. 실제로 unsafePerformIO이라는 기본 라이브러리에 IO a -> a 유형의 기능이 있습니다.

그러나 unsafe 부분이 이유가 있습니다. 그 사용이 정당하다고 여겨지는 경우는 거의 없습니다. 대단히 조심스럽게 사용되는 탈출구입니다. 대부분의 경우 자신을 버리는 대신에 괴물을 들게합니다.

왜 일반적으로 IO a에서 a으로 갈 수 없습니까? 적어도 순전히 전혀 순수하지 않은 겉으로보기에 순수한 함수를 가짐으로써 규칙을 깨뜨릴 수 있습니다. 이 작업을 수행하는 것이 일반적인 관행 인 경우 유형 서명 및 컴파일러에서 검증 한 모든 작업이 전혀 의미가 없습니다. 모든 정확성 보장은 창 밖으로 나옵니다.

하스켈은 (일반적으로) 불가능하기 때문에 부분적으로 흥미 롭습니다.

특히 getLine 문제에 대한 접근 방법은 다른 답변을 참조하십시오.

관련 문제