2014-04-18 4 views
4

최근 하스켈을 배우기 시작했습니다. 나는 배열의 임의 요소 선택 프로그램을 작성하려고 해요 :하스켈 IO Int 및 Int

import System.Random 

randomInt :: (Int, Int) -> IO Int 
randomInt range = randomRIO range :: IO Int 

choseRandom :: [a] -> a 
choseRandom list = 
    length list 
    >>= 
     (\l -> randomInt(0,l-1)) 
     >>= 
      (\num -> (list !! num)) 

main :: IO() 
main = undefined 

을 나는 다음과 같은 오류 얻을 : 내가 잘못 뭘하는지

Build FAILED 

C:\Users\User\Haskell\Real\src\Main.hs: line 7, column 9: 
    Couldn't match expected type `IO Int' with actual type `Int' 

    In the return type of a call of `length' 

    In the first argument of `(>>=)', namely `length list' 

    In the first argument of `(>>=)', namely 

     `length list >>= (\ l -> randomInt (0, l - 1))' 

를? , 당신이 얻을 >>=를 사용할 필요가 없습니다 둘째

choseRandom :: [a] -> IO a 

: 당신이 choseRandom 내에서 IO를 사용하고 있기 때문에 내가 당신이 유형의 서명을 변경해야 할 첫 번째 시간

답변

7

에 대한 모나드를 처리하는 것이 어렵다 리스트의 길이. >>=

Monad m => m a -> (a -> m b) -> m b 

length의 유형이다 [a] -> Int 입력이 있으므로 length list의 종류 모나드하지 않다 Int이다. randomInt를 호출 할 때 당신은 직접 계산할 수

:

choseRandom :: [a] -> IO a 
choseRandom list = fmap (\num -> (list !! num)) (randomInt(0, length list)) 
+3

일단 'fmap'아이디어를 얻으면 추한'(\ num -> (list !! num))'은'(list !!)'로 단축 될 수 있습니다. – Ingo

4

과 동일

choseRandom :: [a] -> IO a 
choseRandom list = 
    randomInt(0, length list) >>= (\num -> return (list !! num)) 

이 작동합니다 :

import System.Random 

randomInt :: (Int, Int) -> IO Int 
randomInt range = randomRIO range :: IO Int 

choseRandom :: [b] -> IO b 
choseRandom list = randomInt (0, length list) >>= \x -> return $ list !! x 

을 나는이 더 관용적 찾기 :

choseRandom list = do 
a <- randomInt (0, length list) 
return $ list !! a 

choseRandom 함수의 문제점은 형식 서명이 잘못되었다는 것입니다. >>= 유형은 m a -> (a -> m b) -> m b이어야하므로 return을 사용하여 결과를 모나드로 다시 묶어야합니다.

randomInt (0, length list) 당신에게 IO Int을 줄 것이다 당신이에서 Int을 추출 할 >>= 기능을 사용하여 :

는 그래서는 다음과 같이 작동합니다. 이제 !! 함수를 사용하여 목록에서 해당 요소를 추출 할 수 있습니다. 출력 유형이 m b이어야하므로 return을 사용하여 모나드로 다시 감싼다.

7

It's hard for me to deal monads for first times

예, 구문 지원을 피함으로써 더 어렵게 만듭니다. 다음과 같이 작성하십시오 :

이 모양이 훨씬 좋지 않습니까?

요점 : randomRIO 함수는 해당 유형이 나타내는 것처럼 일부 전역 상태 (아마도 시스템 타이머)를 사용합니다. 따라서 의 결과는 IO 모나드에만 사용할 수 있습니다.

대안은 main 함수에서 임의 생성기를 초기화하고이 생성기를 "임의"값이 필요한 순수 함수로 전달하는 것입니다.

+0

그것은 시스템 타이머가 아니라 라이브러리의 순수 함수가 명시 적으로 전달하는 것과 같은 종류의 생성자 인'StdGen' 유형의 내용을 가진 공유 가능한 가변 변수입니다. IO 기반 난수 함수는 본질적으로 순수 함수를 중심으로 읽기 및 쓰기를 해당 변수에 랩핑합니다. –

3

먼저 형식 서명을 choseRandom으로 수정해야합니다. 둘째로 나는 do 표기법을 사용하면 훨씬 쉽게 찾을 수있을 것이라고 생각합니다.

choseRandom :: [a] -> IO a 
choseRandom list = do 
    let l = length list 
    num <- randomInt (0, l-1) 
    return (list !! num) 
+0

모나드에 대해 배우고있는 사람에게는 처음에는 의사 표기법을 사용하지 않는 것이 좋습니다. – Simon