하스켈 에러메시지 질문입니다
글쓴이: somoe232 / 작성시간: 일, 2014/12/28 - 3:47오후
하스켈을 배워보려고 최근 하스켈 위키에 있는 99문제를 풀어보고 있습니다.
그 중 24번 문제에서 막혔다가 $만 넣어주면 되는 걸 알고 좀 허무했는데요.
해결하고 난 후에도 에러메시지 뜻을 알기 힘들어 어떻게 이런 에러메시지가 나오게 됐는지 알고싶어서 질문올립니다.
import System.Random rnd_select :: [a] -> Int -> IO [a] rnd_select xs n = if n > 0 then do t <- rnd_select xs (n-1) r <- randomRIO (1, length xs - 1) return (xs !! r) : t -- return의 우선순위가 :보다 높아 $를 return뒤에 넣으면 해결됩니다. se return []
위 코드를 실행하면 아래 에러가 뜨는데, [[a]]타입이 갑자기 왜 생긴 건지 도통 영문을 모르겠습니다;;
저 그대로 해석하면 (return (xs !! r)) : t가 되지만, (IO a) : [a]정도가 아닌가요?
Couldn't match type ‘[]’ with ‘IO’ Expected type: IO [a] Actual type: [[a]] In a stmt of a 'do' block: return (xs !! r) : t In the expression: do { t <- rnd_select xs (n - 1); r <- randomRIO (1, length xs - 1); return (xs !! r) : t } In the expression: if n > 0 then do { t <- rnd_select xs (n - 1); r <- randomRIO (1, length xs - 1); return (xs !! r) : t } else return []
Forums:
do 안을 다시 써보면rnd_select xs
do 안을 다시 써보면
rnd_select xs (n-1) >>= \t ->
randomRIO (1, length xs - 1) >>= \r ->
return (xs !! r) : t
인데 마지막 >>= 연산자의 오른쪽이 y:ys 형태이므로 하나의 모나드인 List(또는 [])가 여기에서의
모나드인가 보다 판단하고 그래서 return (xs !! r)은 형이 [a]가 되고 다시 : 연산자 때문에 전체가
[[a]]인 걸로 판단하기 때문이 아닐까 생각합니다.
읏..
실수로 로그인하지 않고 댓글을 달았네요. 추가로 질문이 있어요.
잘 납득이 안 가는 부분이..
[a] : [a]가 [[a]]가 될 수 있나요? 그러려면 [a] : [[a]]여야 한다고 생각했는데요.
제가 아직 모나드조차 제대로 이해하질 못해서 return구문이 어떻게 동작하는지도 짐작이 힘드네요.
그나마 알고 있는 건 return (xs !! r) : t가 Monad Int : [a]가 되고 esrevinu님 말씀은 저 모나드를 []로 생각하면 된다는 얘기 같은데 (:)타입에 저걸 허용할 지 잘 모르겠고 (>>=)연산을 쓴다 해도 [a]정도밖에 안 될 것 같은데요.
저도 하스켈 잘 모릅니다. 전에 조금 공부해서 답글을
저도 하스켈 잘 모릅니다. 전에 조금 공부해서 답글을 달았습니다.
그래도 제 답이 엄밀하지는 않겠지만 어느 정도 답은 된다고 생각합니다.
컴파일러가 모든 것을 정확하게 따져서 완벽한 메시지를 주지는 않겠지요.
하스켈은 형을 다 안 써 주어도 형을 유추하니까 컴파일러가 형을 유추해 나가다가
모순이 일어나는 곳에서 컴파일 오류를 내겠죠.그때에 잘못된 점을 메시지로
출력할 것이고요. 자기가 모든 것을 따져보지 않아도 모순이 있음을 알 수 있겠지요.
즉, 뒤에 있는 t가 무슨 형인지 따져보지 않아도 결과가 y:ys 형인데 y가 [a]형이니까
[[a]]형이 최종 결과라고 판단하고 오류를 냈을 것으로 보입니다.
저도 잘 모르지만 모나드는 type class인데 어떤 형이 특정 인터페이스를 가지면
해당 type class에 속하는 type이 됩니다. 모나드의 경우 return과 >>=, 이 둘이었던 것 같은데
List도 모나드라는 말은 List에도 return과 >>= 인터페이스가 있다는 말입니다.
같은 return과 >>=라도 거기서의 모나드가 무엇이냐에 따라서 해당 형의 return과 >>=를 쓸 것이고요.
return은 a라는 형을 모나드로 싸서 돌려 주므로 List의 경우 [] a가 결과가 됩니다.
저 return이 IO 모나드의 것이었다면 IO a가 되었겠지만요.
컴파일이 큰 범위에서 작은 범위로 이루어진다면 >>= 뒤에 (:) y ys 형태가 와서 우측이 (:) 최종 결과인 List b이므로
모나드가 List일 것으로 판단하였을 것이고 그래서 []와 IO가 맞지 않는다고 말하는 것으로 보입니다.
그런 후에 IO [a]가 아닌 [] b 형이긴 한데 b가 뭔지 사용자에게
알려주면 좋아할 것 같아 그 다음 작은 범위로 들어 가서 return (xs !! r)을 따져 보는데
return은 여기서 >>=의 분석의 영향으로 List의 것으로 판단할 것입니다.
그래서 return 함수의 결과는
감사합니다. 이해에 많은 도움이 되었습니다.
좀 시간이 걸렸지만 이제 전부 납득할 수 있을 것 같네요 ㅎㅎ
알고나면 별 거 아니어 보이는데 왜 이리 헤맨 건지... 여튼간에 감사드립니다.
댓글 달기