[haskell] 이 Haskell 코드에서 “무한 유형”오류가 발생하는 이유는 무엇입니까?

저는 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를 목록이 아닌 요소로 취급했습니다.

“무한 유형”오류 처리 지침 :

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



답변

문제는 마지막 절에 있습니다. 여기서 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


답변

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

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'

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


답변

내가 틀렸을 수도 있지만 더 어려운 문제를 해결하려는 것 같습니다. 귀하의 버전은 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을 배우고있을 때 제 교수님이 우리가하기를 원했던 일이기 때문에 여러분이하고 싶은 일이라고 가정하고 있습니다. 물론 나는 완전히 나갈 수있다.


답변

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

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

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


답변