2010-06-13 4 views
8

프로그래밍 계몽의 여정의 일부로 하스켈의 세계에 내 발가락을 담았습니다 (절차에서 OOP로, 지금은 기능적으로 동시 진행).학습 하스켈지도, 폴드, 루프 및 재귀

나는 온라인으로 Haskell Evaluator을 시도 해왔다.

그러나 지금은 문제에 붙어있어 :

숫자의 배열의 총합을 제공하는 간단한 함수를 만듭니다. 나를 위해 절차 언어이에서

충분히 쉽다 (사용 재귀) (C#을) :

private int sum(ArrayList x, int i) 
{ 
    if (!(x.Count < i + 1)) { 
     int t = 0; 

     t = x.Item(i); 
     t = sum(x, i + 1) + t; 
     return t; 
    } 
} 

하스켈의 모든 아주 좋은 그러나 나의 시도가 실패한 따라서이었다

let sum x = x+sum in map sum [1..10] 

이 다음과 같은 오류가 발생했습니다 (위에서 언급 한 웹 사이트에서) :

Occurs check: cannot construct the infinite type: a = a -> t 

지난 30 분 동안 하스켈만을 사용했음을 명심하십시오!

나는 단순히 대답만을 찾고있는 것이 아니라 더 많은 설명을하고있다.

답변

16

그것의 더 많은 설명.

=의 왼쪽에는 x에 적용되는 기능으로 sum을 사용합니다. 컴파일러에서는 x 형식을 알지 못하므로 컴파일러에서 형식 변수 a을 사용하여 "x 형식"을 나타냅니다. 따라서 컴파일러는 함수 sum의 결과 유형을 알지 못하므로 다른 유형 변수 인이 유형 t을 선택하여 결과 유형을 나타냅니다. 이제 컴파일러는 x 유형이 a -> t (함수 허용 at 반환)이라고 생각합니다.

= 오른쪽에 xsum을 추가하십시오. Haskell에서는 모든 종류의 숫자를 추가 할 수 있지만, 과 같은 유형이있는 경우에만 두 개의 숫자를 추가 할 수 있습니다. 그래서 여기서 컴파일러는 sumx과 동일한 유형, 즉 유형이 a 인 것으로 가정합니다.

그러나 하스켈에서는 식별자가 하나의 유형 — 일 가능성이 있지만 복잡하지만 유형은 하나만 있습니다. 이것은 그 유형 '기호 양쪽에 동일해야 sum 포함하므로 컴파일러 a이 방정식의 t 범위가 없습니다 식

a = a -> t 

을 해결하기 위해 시도한다. 간단히 할 수 없습니다. a이 없으므로 a은 자신을 인수로 받아들이는 함수와 같습니다. 따라서 오류 메시지가 발생합니다.

cannot construct the infinite type: a = a -> t 

모든 설명이 있지만 큰 오류 메시지는 아닙니다. 그렇습니까? 하스켈에

에 오신 것을 환영합니다 :-)


P.S. 초보자에게 더 좋은 오류 메시지를주는 "Haskell 학습을위한 헬륨"을 즐기실 수 있습니다.

let sum x = x+sum 

합계의 유형이 경우 어떤 것이의 첫 번째 부분에서

+0

이것은 내가 찾고 있던 포괄적 인 설명이었다. 이것을 읽고 추가 읽기를 한 후에 나는 이제 그것을 조금 더 잘 이해합니다. – Darknight

12

'sum'은 값 목록을 가져 와서 단일 값으로 줄입니다. 명시 적 루프로 작성할 수 있습니다 (하스켈에는 루프 키워드가없고 재귀를 사용함을 기억하십시오). tail-recursive 스타일로,보다 효율적으로

mysum []  = 0 
mysum (x:xs) = x + mysum xs 

또는 : 정의 목록의 모양에 따라, 두 부분으로 구성하는 방법을 참고 그러나

mysum xs = go 0 xs 
    where 
     go n []  = n 
     go n (x:xs) = go (n+x) xs 

, 하스켈 제어 구조의 풍부한 라이브러리를 가지고 그 게으른 목록에서 작동합니다. 이 경우 의 단일 값 목록을 축소 함수로 지정할 수 있습니다.

Prelude> foldr (+) 0 [1..10] 
55 

귀하의 실수는 한 번에 목록을 변환 지도, 하나 개의 요소를 사용하는 것이었다 아니라, 예를 들면 다음과 같습니다

mysum xs = foldr (+) 0 xs 

:로

그래서 mysum 쓸 수 있습니다 접미어.

함수 프로그래밍의 핵심 개념에 대한 느낌을 얻으려면 하스켈에 대한 소개부터 시작하는 것이 좋습니다 (아마도 "Programming in Haskell"). 다른 좋은 입문 자료가 설명되어 있습니다 in this question.

+0

는 I 모르겠습니다 = (+) foldl 합에

하자 합 무엇 0 플레이의 중요성, 제발 제로의 사용에 확장 할 수 있습니까? – Darknight

+0

0은 접기의 누적 매개 변수에 대한 초기 값입니다. 원본 소스의 't'값입니다. –

1

당신은 좋은 튜토리얼을 읽을 필요가 있습니다. 큰 오해가 있습니다.

먼저 목록이 아니라 배열이라고 가정합니다. 배열은 Haskell에 존재하지만, 초보자 수준에서는 만나지 않습니다. (1-10의 숫자 목록 인 [1..10]을 사용하는 것은 말할 필요도 없음).

실제로 내장하고 합계라고, 그래서 우리는 다른 우리의 무언가를 호출해야한다 원하는 기능 new_sum : 나는 대답하지만 위해 단순히 찾는 게 아니에요

new_sum [] = 0 
new_sum (h:t) = h + (sum t) 
+0

패턴 일치 구문이 잘못되었습니다. –

+0

고마워, 코드를 시도하지 않고 내 유형을 확인하지 않았다. 결정된. –

+0

이해가 어려웠던 것은 (합계) 부분 이었지만 Norman의 대답과 추가 읽기 후에는 이제 의미가 있습니다. – Darknight

0

살펴 보자? 그것은 숫자를 취하고 숫자 등을 취하는 함수를 반환하는 함수를 반환합니다. 합계 x = + x 을 사용하면 숫자를 취하여 함수 + x를 반환합니다. . 및 let sum = + 은 두 개의 정수를 취하여 추가하는 함수를 반환합니다.

이제 두 번째 부분을 살펴 보겠습니다. in map sum [1..10] map은 하나의 인수의 함수를 취하여 목록의 모든 요소에 적용합니다.어큐뮬레이터를 쐐기로 채울 여지가 없으므로 foldl, foldr과 같은 다른 목록 기능을 살펴 보겠습니다. 이 두 함수는 두 개의 인수와 목록 및 시작 값의 함수를 취합니다. foldl과 foldr의 차이는 시작하는쪽에 있습니다. L은 존재하므로 1 + 2 + 3 등 및 R을 방치 오른쪽 10 + 9 + 8 등 0 [1..10]