하스켈 에러메시지 질문입니다

somoe232의 이미지

하스켈을 배워보려고 최근 하스켈 위키에 있는 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 []
esrevinu의 이미지

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]]인 걸로 판단하기 때문이 아닐까 생각합니다.

somoe232의 이미지

실수로 로그인하지 않고 댓글을 달았네요. 추가로 질문이 있어요.

익명 사용자의 이미지

[a] : [a]가 [[a]]가 될 수 있나요? 그러려면 [a] : [[a]]여야 한다고 생각했는데요.
제가 아직 모나드조차 제대로 이해하질 못해서 return구문이 어떻게 동작하는지도 짐작이 힘드네요.
그나마 알고 있는 건 return (xs !! r) : t가 Monad Int : [a]가 되고 esrevinu님 말씀은 저 모나드를 []로 생각하면 된다는 얘기 같은데 (:)타입에 저걸 허용할 지 잘 모르겠고 (>>=)연산을 쓴다 해도 [a]정도밖에 안 될 것 같은데요.

esrevinu의 이미지

저도 하스켈 잘 모릅니다. 전에 조금 공부해서 답글을 달았습니다.
그래도 제 답이 엄밀하지는 않겠지만 어느 정도 답은 된다고 생각합니다.
컴파일러가 모든 것을 정확하게 따져서 완벽한 메시지를 주지는 않겠지요.
하스켈은 형을 다 안 써 주어도 형을 유추하니까 컴파일러가 형을 유추해 나가다가
모순이 일어나는 곳에서 컴파일 오류를 내겠죠.그때에 잘못된 점을 메시지로
출력할 것이고요. 자기가 모든 것을 따져보지 않아도 모순이 있음을 알 수 있겠지요.
즉, 뒤에 있는 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 함수의 결과는

 형이 되고 최종은 [[c]]이 되는데
여기서 끝내면 사용자가 c는 어디서 온 건지 의아해 하니까 더 따져 보는데 (xs !! r)이 a이니까 c == a가 되고
그래서 최종결과가 [[a]]가 되는 것으로 유추했을 것 같습니다. 물론 뒤의 t가 [[a]]가 아니므로 모순이 있지만 그 이전에 다른
모순을 발견하였고 t까지 볼 필요가 없었을 것입니다.
 
소스에서 마지막 t를 [t]로 바꿔 보십시오. 똑같은 메시지가 나옵니다.
 
추가:
(xs !! r)(3 :: Int)로 바꿔도 똑같이 [[a]]라고 나오는 것으로 보아 
최종 결과가 (:) y ys임으로부터 바로 [[a]]로 판단한 것 같네요.
(:) :: d -> List d -> List d
이므로
(>>=) :: List d -> (d -> List d) -> List d
로 판단하였을 것 같고
따라서 
return :: e -> List e
가 되는데 d가 [a]라고 어떻게 판단했을까요?
>>=의 앞을 [3]으로 바꿔 봐도 [[a]]라고 나오는 걸로 봐서 
IO [a]여야 하는데 : 연산이 있는 걸로 보아 그냥 IO 대신 List 모나드라고
판단한 것으로 보입니다. 생각보다 친절하지 않네요. 
[3] >>= \r ->
[3]
이렇게 써도 [[a]]라고 나옵니다.
 
또 추가:
앞의 형 선언을 없애면 또 다릅니다.
[3] >>= \r ->
[3]
라고 바꾸고 해도 넘어 갑니다. ㅎㅎ
그럼 rnd_select 형은 다음으로 결정됩니다.
rnd_select :: (Ord a, Num [t1], Num a) => t -> a -> [[t1]]

somoe232의 이미지

좀 시간이 걸렸지만 이제 전부 납득할 수 있을 것 같네요 ㅎㅎ
알고나면 별 거 아니어 보이는데 왜 이리 헤맨 건지... 여튼간에 감사드립니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.