이 Haskell 코드에서 "무한 유형"오류가 발생하는 이유는 무엇입니까?


82

저는 Haskell을 처음 접했고 이해할 수없는 "무한 유형을 구성 할 수 없습니다"라는 오류에 직면했습니다.

사실 그 이상으로이 오류가 무엇을 의미하는지에 대한 좋은 설명을 찾을 수 없었기 때문에 기본 질문을 넘어서 "무한 유형"오류에 대해 설명해 주시면 정말 감사하겠습니다.

코드는 다음과 같습니다.

intersperse :: a -> [[a]] -> [a]

-- intersperse '*' ["foo","bar","baz","quux"] 
--  should produce the following:
--  "foo*bar*baz*quux"

-- intersperse -99 [ [1,2,3],[4,5,6],[7,8,9]]
--  should produce the following:
--  [1,2,3,-99,4,5,6,-99,7,8,9]

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:y:xs) = x:s:y:intersperse s xs

그리고 다음은 인터프리터에로드하려는 오류입니다.

Prelude> :load ./chapter.3.ending.real.world.haskell.exercises.hs
[1 of 1] Compiling Main (chapter.3.ending.real.world.haskell.exercises.hs, interpreted )

chapter.3.ending.real.world.haskell.exercises.hs:147:0:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `intersperse'
Failed, modules loaded: none.

감사.

-

다음은 Haskell의 "무한 유형"오류를 처리하기위한 수정 된 코드와 일반적인 지침입니다.

수정 된 코드

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) =  x ++ s:intersperse s xs 

문제 :

내 타입 시그니처는 두 번째 매개 변수가 목록의 목록이라고 말한다. 따라서 "s (x : y : xs)"에 대해 패턴 매칭을했을 때 x와 y는 목록 이되었습니다 . 하지만 저는 x와 y를 목록이 아닌 요소로 취급했습니다.

"무한 유형"오류 처리 지침 :

대부분의 경우이 오류가 발생하면 다루고있는 다양한 변수의 유형을 잊어 버리고 변수가있는 것과 다른 유형 인 것처럼 사용하려고 시도한 것입니다. 모든 것이 어떤 유형인지, 어떻게 사용하는지주의 깊게 살펴보면 일반적으로 문제가 발견됩니다.


2
또 다른 좋은 팁 : 유형을 명시 적으로 선언하십시오. 이것은 컴파일러에게 검사 할 무언가를 제공합니다.
Paul Johnson

3
그래서 이것은 문제를 해결하는데 왜 컴파일러는 "무한한 유형을 구성 할 수 없습니까?"라고 말합니다. 그게 무슨 뜻입니까? 문제가 이러한 작업을 지원하지 않는 유형에 대해 작업을 수행하려는 경우 컴파일러가 그런 말을하지 않는 이유는 무엇입니까?
freedrull 2010 년

11
질문의 구조에 +1 (질문-수정 됨-문제는-지침)
Dacav

2
@freedrull : 컴파일러에게 유형 매개 변수 "a"를 "목록의 a"로 "채워야"한다고 말했기 때문에 오류가 그렇게 표현되었습니다. 그것은 내 커피 잔에 내 커피 잔의 복사본이 포함되어 있다는 것과 같습니다. 정말 말도 안되는 재귀 적 정의입니다 (또는 적어도 Haskell에서는 유효하지 않은 것으로 정의됩니다). 그래서 "무한 유형을 구성 할 수 없습니다"라고 말합니다. 문제는 a를 기반으로하는 유형 매개 변수로 다른 작업을 수행 할 수 있다는 것입니다. 예를 들어, 해당 유형 매개 변수를 "Maybe a"로 채울 수 있습니다. 그래서 제가하고 있던 일은 괜찮 았지만 제가 한 특정한 일은 괜찮지 않았습니다.
Charlie Flowers

1
@freedrull : 컴파일러는 코드가와 관련된 값을 사용하여 여러 가지 작업을 수행한다는 사실을 발견했습니다 a. 따라서 그 중 하나를 가리키고 "이 유형에 대해 지원되지 않는 작업입니다"라고 말할 수 없습니다. 그러나 그들은 함께 만족하는 유형에 대한 요구 사항을 추가합니다 a = [a]. 컴파일러는 그것이 불가능하다는 것을 알고 있으므로이를 알려줍니다. 그 요구 사항을 야기한 코드의 어떤 부분이 잘못된 부분인지 알지 못합니다. 그게 당신이 무엇에 따라 달라 위한 의미하는 코드를.

답변:


36

문제는 마지막 절에 있습니다. 여기서 x와 y는 목록이지만 요소로 취급합니다. 이것은 작동합니다.

intersperse _ [] = []
intersperse _ [x] = x 
intersperse s (x:y:xs) = x ++ [s] ++ y ++ intersperse s xs

무한 유형 오류는 : 연산자의 유형이 a-> [a]-> [a] 인 반면에 [a]-> a-> [a]로 취급하기 때문에 발생합니다. 즉, [a]는 a는 무한 중첩 목록임을 의미합니다. 그것은 허용되지 않습니다 (그리고 당신이 의미하는 바가 아닙니다).

편집 : 위 코드에는 또 다른 버그가 있습니다. 그것은해야한다:

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) = x ++ [s] ++ intersperse s xs

1
감사. 두 가지를 모두 알아 내고 여기로 돌아와서 귀하의 응답을 보았습니다. 이는 저에게 훌륭한 검증이었습니다. 당신은 또한 나보다 내 버그를 더 잘 수정했습니다. 내 버그는 y와 xs 사이의 구분 기호를 건너 뛰는 것입니다. 이를 수정하기 위해 다음과 같은 또 다른 수준의 패턴 일치를 도입했습니다. intersperse s (x : y : []) = x ++ s : y intersperse s (x : y : xs) = intersperse s [x, y] ++ s : intersperse s xs하지만 추가 수준 없이도 내 버그를 수정 한 것 같습니다.
Charlie Flowers

2
제가 배운 교훈은 다음과 같습니다. " '무한 유형'오류에 직면하면 어떤 유형을 다루고 있는지 잊어 버릴 것이므로 의도하지 않은 작업을 수행 할 수 있습니다. 모든 변수의 유형을주의 깊게 살펴보십시오. 일반적으로 문제가 발견됩니다. " 추가하거나 변경할 사항이 있습니까?
Charlie Flowers

그것은 확실히 맞습니다. 무한 유형은 허용되지 않으므로 무한 유형 오류는 함수가 어딘가에 잘못된 유형의 인수를 수신함을 의미합니다. RWH에 행운을 빕니다 :)
Stephan202

where you treat x and y as elements, while they are lists.왜 그들은 목록에 있지만 설명하지 않았습니까? 에서 x:xs, x요소, 바로입니까? 나는 그것도 똑같기를 바랬다 x:y:xs. 또한 목록 인 경우 몇 개의 요소를 포함하여 어떻게 분할됩니까? 하나?
Nawaz

6

종종 명시 적 유형 정의를 추가하면 컴파일러의 유형 오류 메시지가 더 의미가있을 수 있습니다. 그러나이 경우 명시 적 타이핑은 컴파일러의 오류 메시지를 더 악화시킵니다.

ghc가 intersperse의 유형을 추측하게하면 어떻게되는지보세요.

Occurs check: cannot construct the infinite type: a = [a]
  Expected type: [a] -> [[a]] -> [[a]]
  Inferred type: [a] -> [[a]] -> [a]
In the second argument of `(:)', namely `intersperse s xs'
In the second argument of `(:)', namely `y : intersperse s xs'

그것은 분명히 코드의 버그를 가리 킵니다. 이 기술을 사용하면 다른 사람들이 제안한 것처럼 모든 것을 쳐다보고 유형에 대해 열심히 생각할 필요가 없습니다.


3

내가 틀렸을 수도 있지만 더 어려운 문제를 해결하려는 것 같습니다. 귀하의 버전은 intersperse배열에 값을 산재 할뿐만 아니라 한 수준으로 평평하게 만듭니다.

ListHaskell 의 모듈은 실제로 intersperse 기능을 제공합니다. 목록의 모든 요소 사이에 주어진 값을 넣습니다 . 예를 들면 :

intersperse 11 [1, 3, 5, 7, 9] = [1, 11, 3, 11, 5, 11, 7, 11, 9]
intersperse "*" ["foo","bar","baz","quux"] = ["foo", "*", "bar", "*", "baz", "*", "quux"]

저는 이것이 제가 Haskell을 배우고있을 때 제 교수님이 우리가하기를 원했던 일이기 때문에 여러분이하고 싶은 일이라고 가정하고 있습니다. 물론 나는 완전히 나갈 수있다.


1
댓글 주셔서 감사합니다. 하지만이 경우에는 "Real World Haskell"의 3 장 끝에서 연습 7을 수행하고 있기 때문에 한 단계 평평하게 만들고 싶습니다.
Charlie Flowers

알았어. 책이 있었다면 글을 쓰기 전에 확인했을 것입니다. 아아, 제가 할 수있는 것은 추측뿐이었습니다. 어쨌든 정렬되어 기쁘다. :-)
Samir Talwar

5
:이 책의 내용은 자유롭게 사용할 수 온라인으로 만들어 book.realworldhaskell.org
Stephan202

우수한. 북마크 됨. 링크 주셔서 감사합니다. 내년에 하스켈 연구소에서 도움을 드릴 것입니다.
Samir Talwar

0

또한 오류의 의미를 설명하는 이것을 발견 했습니다 .

인터프리터 / 컴파일러가이 오류를 줄 때마다 형식 매개 변수화 된 튜플을 형식 매개 변수로 사용하고 있기 때문입니다. 유형 변수를 포함하는 함수의 유형 정의를 제거 하면 모든 것이 올바르게 작동합니다 .

나는 그것을 수정하고 함수 유형 정의를 유지하는 방법을 여전히 알 수 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.