복붙노트

[SCALA] 기능적 프로그래밍 - 재귀에 대한 강조, 왜 많은?

SCALA

기능적 프로그래밍 - 재귀에 대한 강조, 왜 많은?

나는 [FP가 (스칼라를 사용하여) 기능 프로그래밍에 도입 얻고있다. 내 최초의 교훈으로부터 오는 것은 FPS 재귀에 크게 의존한다는 것이다. 그리고 또한 재귀 함수를 작성하는 것입니다 반복 물건을 할 수있는 유일한 방법은 순수 FPS에서처럼 보인다.

때문에 재귀의 사용량이의 StackoverflowExceptions 인해 긴 권선 재귀 호출에 일반적이었다에 대해 FPS 걱정해야한다고 다음 일을 보인다. 이것은 (이후 스칼라 V2.8에서 stackframes의 유지 보수 및 @tailrec 주석에 꼬리 재귀 관련 최적화) 몇 가지 최적화를 도입하여 달려 드는되었다

재귀는 함수형 프로그래밍 패러다임에 중요한 이유 누군가가 가르치 려 주실 래요? 우리가 반복적으로 물건을 할 경우 "위반"도착 함수형 프로그래밍 언어의 사양에 뭔가 있나요? 그렇다면, 나는뿐만 아니라 알고 싶어입니다.

PS : 나는 함수형 프로그래밍에 초보자 그래서 그들은 설명 할 경우 / 기존 자원 날 지점 주시기 내 질문에 대답 생각합니다. 또한 나는 스칼라 특히뿐만 아니라 반복적 인 물건을위한 지원을 제공한다는 것을 이해한다.

해결법

  1. ==============================

    1.교회 튜링의 논문은 서로 다른 계산 가능성 모델 사이의 동등성을 강조한다.

    교회 튜링의 논문은 서로 다른 계산 가능성 모델 사이의 동등성을 강조한다.

    재귀를 사용하여 몇 가지 문제를 해결하는 동안 우리는 변경 가능한 상태를 필요로하지 않으며, 가능한이 메이크업은 간단 측면에서 의미를 지정할 수 있습니다. 따라서 솔루션은 형식적인 의미에서 간단하게 할 수 있습니다.

    내 생각 프롤로그 쇼 더 나은 기능 언어와 재귀의 효과 (그것이 반복이없는), 그것을 사용할 때 우리가 발생하는 실제적인 한계.

  2. ==============================

    2.부작용없이 순수 함수형 프로그래밍 수단. 당신은 예를 들어 루프를 작성하는 경우 어떤 수단은, 루프의 몸은 부작용을하지를 생성 할 수 있습니다. 당신이 당신의 루프가 뭔가를하고 싶은 경우에 따라서, 그것은 이전 반복의 결과를 재사용하고 다음 반복을 위해 무언가를 생산한다. 따라서, 루프의 몸은 매개 변수로 이전 실행의 결과를 측정하고 자신의 결과 다음 반복 자체를 호출하는 기능입니다. 이 직접 루프 재귀 함수를 작성하는 동안 큰 장점이 없습니다.

    부작용없이 순수 함수형 프로그래밍 수단. 당신은 예를 들어 루프를 작성하는 경우 어떤 수단은, 루프의 몸은 부작용을하지를 생성 할 수 있습니다. 당신이 당신의 루프가 뭔가를하고 싶은 경우에 따라서, 그것은 이전 반복의 결과를 재사용하고 다음 반복을 위해 무언가를 생산한다. 따라서, 루프의 몸은 매개 변수로 이전 실행의 결과를 측정하고 자신의 결과 다음 반복 자체를 호출하는 기능입니다. 이 직접 루프 재귀 함수를 작성하는 동안 큰 장점이 없습니다.

    사소한 일을하지 않는 프로그램은 어떤 점에서 뭔가를 반복해야합니다. 이 수단 함수형 프로그래밍에 대한 프로그램은 재귀 함수를 사용한다.

  3. ==============================

    3.당신이 반복적으로 일을하는 요구 사항에 대한 제공이 기능은 불변 변수입니다.

    당신이 반복적으로 일을하는 요구 사항에 대한 제공이 기능은 불변 변수입니다.

    (의사)에서리스트의 합을 산출하는 간단한 함수를 고려

    fun calculateSum(list):
        sum = 0
        for each element in list: # dubious
            sum = sum + element # impossible!
        return sum
    

    이제,리스트의 각 반복의 요소는 다르지만, 우리는이 문제를 없애 람다 인수 foreach는 기능을 사용하려면이 옵션을 다시 작성할 수 있습니다 :

    fun calculateSum(list):
        sum = 0
        foreach(list, lambda element:
            sum = sum + element # impossible!
        )
        return sum
    

    또, 합계 변수의 값은, λ의 각각의 실행에서 변경되어야한다. 그렇지 개의 mutate 상태를 수행하는 방법으로 그것을 다시 작성해야하기 때문에 이러한 현상이 불변 변수의 언어로 불법입니다 :

    fun calculateSum([H|T]):
        return H + calculateSum(T)
    
    fun calculateSum([]):
        return 0
    

    자,이 구현은 많은 스택에 밀어하고 통화에서 터지는 필요합니다, 모든 작은 작업이 작업을 수행하는 프로그램이 매우 빠르게 실행되지 않을 것입니다. 따라서, 우리는 컴파일러가 꼬리를 호출 최적화를 할 수 있도록, 꼬리 재귀 수를 재 작성 :

    fun calculateSum([H|T], partialSum):
        return calculateSum(T, H + partialSum)
    
    fun calculateSum([], partialSum):
        return partialSum
    
    fun calculateSum(list):
        return calculateSum(list, 0)
    

    무기한 루프를 원한다면 물론, 당신은 절대적으로 꼬리 재귀 호출이 필요하거나 그렇지는 오버 플로우 스택 것입니다.

    스칼라의 @tailrec 주석은 당신이 꼬리 재귀있는 기능을 분석 할 수있는 도구입니다. 당신은 "이 기능은 꼬리 재귀"당신이 잘못된 경우 다음 컴파일러는 말할 수 있습니다 주장한다. 기계가가 실행되기 때문에 당신이 얻을 것 모두 같은 상황에서 스칼라에 꼬리를 호출 최적화를 얻을 수 없습니다, 그래서 JVM이 잘 꼬리 호출 최적화를 지원하지 않는 다른 기능 언어에 비해이 스칼라에서 특히 중요하다 다른 함수형 언어에.

  4. ==============================

    4.TL은, DR : 재귀 유도 정의 데이터를 처리하는 데 사용되는

    TL은, DR : 재귀 유도 정의 데이터를 처리하는 데 사용되는

  5. ==============================

    5.재귀 아무것도 '스페셜'이있다. 그것은 프로그래밍과 수학 아무것도 더의 대폭적인 도구입니다. 그러나, 함수형 언어는 일반적으로 최소한의입니다. 그들은 등등 패턴 매칭, 타입 시스템, 지능형리스트와 같은 많은 멋진 개념을 도입 할 수 있지만, 더 후 매우 일반적이고 매우 강력하지만 단순하고 원시적 인 도구에 대한 문법 설탕에 불과하다. 이 도구는 다음과 같습니다 기능 추상화와 기능의 응용 프로그램입니다. 언어 코어의 단순 그것에 대해 훨씬 쉽게 추론을 만들면서 이것은 의식적인 선택입니다. 또한 쓰기 컴파일러 쉬워집니다. 이 도구의 측면에서 루프를 설명 할 수있는 유일한 방법은 함수형 프로그래밍은 재귀에 대한 것을, 그래서 필수적 프로그래머가 생각하는, 재귀를 사용하는 것입니다. 그것은 단순히 모방에 필요한 아닌 그 고토 문을 통해이 문법 설탕을 드롭하고 그래서 그들이에 붙어 최초의 것들 중 하나입니다 수없는 가난한 사람을위한 멋진 루프.

    재귀 아무것도 '스페셜'이있다. 그것은 프로그래밍과 수학 아무것도 더의 대폭적인 도구입니다. 그러나, 함수형 언어는 일반적으로 최소한의입니다. 그들은 등등 패턴 매칭, 타입 시스템, 지능형리스트와 같은 많은 멋진 개념을 도입 할 수 있지만, 더 후 매우 일반적이고 매우 강력하지만 단순하고 원시적 인 도구에 대한 문법 설탕에 불과하다. 이 도구는 다음과 같습니다 기능 추상화와 기능의 응용 프로그램입니다. 언어 코어의 단순 그것에 대해 훨씬 쉽게 추론을 만들면서 이것은 의식적인 선택입니다. 또한 쓰기 컴파일러 쉬워집니다. 이 도구의 측면에서 루프를 설명 할 수있는 유일한 방법은 함수형 프로그래밍은 재귀에 대한 것을, 그래서 필수적 프로그래머가 생각하는, 재귀를 사용하는 것입니다. 그것은 단순히 모방에 필요한 아닌 그 고토 문을 통해이 문법 설탕을 드롭하고 그래서 그들이에 붙어 최초의 것들 중 하나입니다 수없는 가난한 사람을위한 멋진 루프.

    재귀 필요한 다른 점은 여기서 (간접 일 수있다) 재귀 정의 된 데이터 구조를 처리한다. 가장 일반적인 예는리스트 ADT이다. FP에서는 일반적으로이 데이터 목록 유사한 정의 = 무기 호 | A (목록 a를) 지점. 여기 ADT의 정의가 반복적이기 때문에, 그에 대한 처리 기능도 재귀한다. 다시 말하지만, 여기에 재귀 어쨌든 특별한되지 않습니다 : 재귀 방식으로 그러한 ADT의 처리하는 필수 기능적인 언어 모두에서 자연적으로 보인다. 음,의 경우 목록과 같은 ADT 필수적 루프 여전히 채택 될 수 있지만, 다른 경우의 구조를 트리 형태 그들은 할 수 없습니다.

    그래서 재귀에는 아무것도 특별한이 없습니다. 그것은 단순히 기능 응용 프로그램의 또 다른 유형입니다. 현대 컴퓨팅 시스템의 한계 (사실상이다 C 언어에서 제대로 만든 디자인 결정에서 비롯 표준 크로스 플랫폼 어셈블러) 함수 호출은 무한히 중첩 될 수 없기 때문에 그러나, 그들은 꼬리 호출하더라도. 그 때문에, 기능적인 프로그래밍 언어의 설계자는 꼬리 재귀 (스칼라) 또는 사용 trampoling 같은 복잡한 기술 (구 GHC의 CODEGEN)에 중 제한 허용 꼬리 통화를하거나 ASM (현대 GHC의 CODEGEN)에 직접 컴파일합니다.

    TL; DR은 : 더 이상 적어도 그러나, 꼬리 재귀는 단지 때문에 JVM의 한계 스칼라에서 허용 꼬리 호출의 유형 IP보다 FP의 재귀에는 아무것도 특별 없다.

  6. ==============================

    6.부작용을 피하기 함수형 프로그래밍의 기둥 (다른 고차 함수를 사용한다) 중 하나이다.

    부작용을 피하기 함수형 프로그래밍의 기둥 (다른 고차 함수를 사용한다) 중 하나이다.

    당신이 돌연변이에 의존하지 않고 필수적 흐름 제어를 사용합니다 수있는 방법을 상상해보십시오. 그것은 수 있습니까?

    에 대한 물론 (var에 나는 = 0; 나는 <10; 내가 ++) ... 돌연변이에 따라 (I ++). 사실, 조건부 루프 구조는 않습니다. 동안 (뭔가)에서 ... 무언가가 일부 변경 가능한 상태에 따라 달라집니다. 물론은, (진정한) 동안 ... 돌연변이를 사용하지 않습니다. 혹시 그 루프 밖으로 원한다면 당신은 경우 (일) 휴식이 필요합니다. 정말, 돌연변이에 의존하지 않는 재귀가 아닌 다른 메커니즘을 루핑 (비 무한) 생각하려고합니다.

    무엇 (someCollection에 var에 X)에 대해 ...? 이제 우리는 함수형 프로그래밍에 가까워지고 있습니다. 는 x가 루프의 신체 파라미터로 간주 될 수있다. 이름을 재사용하면 값을 재 할당과 동일하지 않습니다. 아마도 루프의 본문에 넌 수율 X (NO 돌연변이)의 관점에서 표현으로 값을 반환.

    정확히 동등하게, 당신은 함수 foo (x)는 본문에 루프의 몸을 움직일 수 ... 다음 고차 함수를 사용하여 그 이상의 someCollection지도 -지도 같은 것을 사용하여 루프 구조를 대체 (foo는, someCollection) .

    하지만 어떻게 라이브러리 기능지도 돌연변이없이 구현? 음, 물론 재귀를 사용! 그것은 당신을 위해 이루어집니다. 그것은 당신이 당신의 반복 구조를 대체하는 고차 함수의 두 번째 필의 사용을 시작하면 재귀 함수를 직접 구현해야 덜 일반적인된다.

    또한, 꼬리 호출 최적화를 재귀 적 정의는 반복적 인 과정에 해당합니다. 당신은이 블로그 게시물을 즐길 수 있습니다 http://blogs.msdn.com/b/ashleyf/archive/2010/02/06/recursion-is-the-new-iteration.aspx

  7. ==============================

    7.내가 함수형 프로그래밍에 필수적인 고려 두 가지 속성이 있습니다 :

    내가 함수형 프로그래밍에 필수적인 고려 두 가지 속성이 있습니다 :

    당신이 필수적 스타일로 프로그래밍하는 경우 이제 할당을 사용해야합니다.

    루프를 고려하십시오. 그것은 인덱스를 가지며, 각각의 반복에 대한 인덱스가 다른 값을 갖는다. 이 인덱스를 반환하는 함수를 정의 할 수 있도록. 당신이 함수를 호출하면 두 번 당신은 다른 결과를 얻을 수 있습니다. 따라서 원칙적으로 2 번을 깨는.

    당신이 원칙을 어기면 이제 함수의 결과가 때 함수가 호출됩니다 얼마나 자주 의존 수 있기 때문에 더 2. 기능 (원칙 1 번) 뭔가 매우 위험하게 주위를 통과하지 않습니다.

  8. ==============================

    8.마지막으로 나는 기능적인 언어 (Clojure에서) 나는 심지어 사용 재귀에 유혹되지 않았다을 사용했다. 최종 결과에 도달 할 때까지 모든 것은, 함수가 다른 함수가 적용되었다되는 일부 제품을 얻기 위해 적용되었다되는 것들의 집합으로 처리 할 수있다.

    마지막으로 나는 기능적인 언어 (Clojure에서) 나는 심지어 사용 재귀에 유혹되지 않았다을 사용했다. 최종 결과에 도달 할 때까지 모든 것은, 함수가 다른 함수가 적용되었다되는 일부 제품을 얻기 위해 적용되었다되는 것들의 집합으로 처리 할 수있다.

    재귀는 대개 g에 대처하기 위해 처리해야하는 여러 항목을 처리 할 수있는 유일한 방법, 그리고 반드시 깨끗한 방법입니다

  9. ==============================

    9.새로운 FP 학습자를 위해서 내가 몇 가지 답변에서 언급 한 제 2 cents.As을 추가하고 싶습니다, 재귀는 불변 변수의 사용을하지만 왜 우리가 그것을 할 필요가 있나요? 우리가 원하는 이유는 그것이 쉽게 병렬 멀티 코어에 프로그램을 실행할 수 있습니다,하지만 때문에? 우리는 단일 코어에서 실행하고 우리가왔다 언제나처럼 행복하지 않을 수 있습니까? 하루 CPU 클럭 사이클에 의해 어떤 과정 콘텐츠가 증가하고 있기 때문에 하루에 더 많은 코어를 추가하는 것보다 그렇게 크게 증가되지 않습니다. 지난 1 년간에서 클럭 속도는 매우 긴 시간에서 자신을하고있다 their.Also FP에 더 많은 트랜지스터를 피팅에 소비자의 컴퓨터와 칩 설계자에 문제가있는 3.0 GHz의 2.7 GHz의 최대 개까지 주변에 있었다, 그러나 선택하지 않았다 이 재귀를 사용하고 클럭 속도가 매년 급증했다으로 메모리가 그 당시에는 매우 비싼하지만 같은 커뮤니티는 OOP와 함께가는 계속하기로 결정 그래서 편집 : 그것은 아주 빨리, 나는 분의 몇했다

    새로운 FP 학습자를 위해서 내가 몇 가지 답변에서 언급 한 제 2 cents.As을 추가하고 싶습니다, 재귀는 불변 변수의 사용을하지만 왜 우리가 그것을 할 필요가 있나요? 우리가 원하는 이유는 그것이 쉽게 병렬 멀티 코어에 프로그램을 실행할 수 있습니다,하지만 때문에? 우리는 단일 코어에서 실행하고 우리가왔다 언제나처럼 행복하지 않을 수 있습니까? 하루 CPU 클럭 사이클에 의해 어떤 과정 콘텐츠가 증가하고 있기 때문에 하루에 더 많은 코어를 추가하는 것보다 그렇게 크게 증가되지 않습니다. 지난 1 년간에서 클럭 속도는 매우 긴 시간에서 자신을하고있다 their.Also FP에 더 많은 트랜지스터를 피팅에 소비자의 컴퓨터와 칩 설계자에 문제가있는 3.0 GHz의 2.7 GHz의 최대 개까지 주변에 있었다, 그러나 선택하지 않았다 이 재귀를 사용하고 클럭 속도가 매년 급증했다으로 메모리가 그 당시에는 매우 비싼하지만 같은 커뮤니티는 OOP와 함께가는 계속하기로 결정 그래서 편집 : 그것은 아주 빨리, 나는 분의 몇했다

  10. from https://stackoverflow.com/questions/12659581/functional-programming-lots-of-emphasis-on-recursion-why by cc-by-sa and MIT license