함수 연산자에서 할당 연산자 나 루프를 사용하지 않는 이유는 무엇입니까?


9

내 함수가 두 가지 요구 사항을 충족하면 Sum 주어진 조건에서 항목이 true로 평가되는 목록에서 항목의 합계를 반환하는 함수가 순수한 함수라고 할 수 있다고 생각합니까?

1) 주어진 i / p 세트에 대해 함수가 호출 될 때 시간에 상관없이 동일한 o / p가 리턴됩니다.

2) 부작용이 없습니다.

public int Sum(Func<int,bool> predicate, IEnumerable<int> numbers){
    int result = 0;
    foreach(var item in numbers)
        if(predicate(item)) result += item;
    return result;
}

예 : Sum(x=>x%2==0, new List<int> {1,2,3,4,5...100});

내가이 질문을하는 이유는 사람들이 할당 연산자와 루프를 피하도록 조언하는 거의 모든 곳이 명령 프로그래밍 스타일이기 때문에 조언을하기 때문입니다. 함수 프로그래밍과 관련하여 루프와 할당 연산자를 사용하는 위의 예제에서 무엇이 잘못 될 수 있습니까?


1
item루프에서 변수가 변경 되면 부작용 이 없습니다. 부작용 이 있습니다 .
Fabio

@Fabio 좋아. 그러나 부작용의 범위를 자세히 설명 할 수 있습니까?
rahulaga_dev 23시 09 분

답변:


16

기능적 프로그래밍에서 차이를 만드는 것은 무엇입니까?

함수형 프로그래밍은 원칙적으로 선언적 입니다. 계산 방법 대신 결과가 무엇인지 말합니다 .

스 니펫의 실제 기능 구현을 살펴 보겠습니다. Haskell에서는 다음과 같습니다.

predsum pred numbers = sum (filter pred numbers)

그것은 분명 어떤 결과가? 따라서 술어를 충족시키는 숫자의 합계입니다. 어떻게 계산 되나요? 상관 없어요, 컴파일러에게 물어보세요.

당신은 아마도 사용하여 말할 수 sumfilter트릭이며이 포함되지 않습니다. 그런 다음이 도우미없이 구현하십시오 (가장 좋은 방법은 먼저 구현하는 것입니다).

사용하지 않는 "Functional Programming 101"솔루션 sum은 다음과 같습니다.

sum pred list = 
    case list of
        [] -> 0
        h:t -> if pred h then h + sum pred t
                         else sum pred t

단일 함수 호출 측면에서 결과가 무엇인지 여전히 분명 합니다. 이 중 하나입니다 0, 또는 recursive call + h or 0에 따라 pred h. 최종 결과가 즉각적으로 명확하지 않더라도 여전히 매우 단호합니다 (조금 연습하면 실제로 for루프 처럼 읽습니다 ).

귀하의 버전과 비교하십시오 :

public int Sum(Func<int,bool> predicate, IEnumerable<int> numbers){
    int result = 0;
    foreach(var item in numbers)
        if (predicate(item)) result += item;
    return result;
}

결과는 어떻습니까? 오, 나는 본다 : 단 하나의 return진술, 놀랄 것도 없다 : return result.

그러나 무엇 result입니까? int result = 0? 옳지 않은 것 같습니다. 당신은 나중에 그것으로 무언가를합니다 0. 좋아, 당신 item은 그것에 s를 추가 합니다. 등등.

물론 대부분의 프로그래머에게는 이와 같은 간단한 기능에서 어떤 일이 발생하는지는 분명하지만 추가 설명을 추가 return하면 갑자기 추적하기가 더 어려워집니다. 모든 코드에 관한 방법 , 그리고 무엇을 알아낼 독자 방치 - 이것은 분명히 매우 필수적 스타일입니다 .

변수와 루프가 잘못 되었습니까?

아니.

그들에 의해 훨씬 쉽게 설명되는 많은 것들이 있으며, 가변 상태가 빠르기를 요구하는 많은 알고리즘이 있습니다. 그러나 변수는 설명, 본질적으로 필수적이다 방법 대신에 무엇을 , 그 값이 몇 줄 이상 또는 몇 개의 루프 반복 한 후에 어떻게 될 것인가의 작은 예측을 제공합니다. 루프는 일반적으로 상태를 이해해야하므로 본질적으로 필수적입니다.

변수와 루프는 단순히 기능적 프로그래밍이 아닙니다.

요약

현재의 funcitonal programming은 패러다임보다 스타일과 유용한 사고 방식에 가깝습니다. 순수한 기능에 대한 강한 선호가이 사고 방식에 있지만 실제로는 그저 작은 부분 일뿐입니다.

가장 널리 사용되는 언어를 사용하면 일부 기능적 구성을 사용할 수 있습니다. 예를 들어 Python에서는 다음 중에서 선택할 수 있습니다.

result = 0
for num in numbers:
    if pred(result):
        result += num
return result

또는

return sum(filter(pred, numbers))

또는

return sum(n for n in numbers if pred(n))

이 함수식은 이런 종류의 문제에 잘 맞고 코드를 짧게 만듭니다 ( 짧을수록 좋습니다 ). 명령 코드를 무의식적으로 대체해서는 안되지만, 적합 할 때는 거의 항상 더 나은 선택입니다.


좋은 설명을 위해 thx!
rahulaga_dev

1
@RahulAgarwal 이 답변이 흥미로울 수도 있지만 , 단계를 설명하는 것과 사실을 확립하는 접선 개념을 멋지게 포착합니다. 또한 "선언적 언어에는 부작용이 있지만 명령형 언어는 포함되지 않습니다"라는 문구가 마음에 듭니다. 일반적으로 함수형 프로그램은 외부 세계를 처리하는 상태 기반 코드 (또는 일부 최적화 된 알고리즘 실행)와 순수하게 기능적인 코드 사이를 깨끗하고 눈에 잘 띄게 잘라냅니다.
Frax

1
@Frax : 감사합니다 !! 내가 살펴볼 게 또한 최근에는 가치의 가치 에 관한 Rich Hickey의 이야기를 접했습니다 . 정말 훌륭합니다. 나는 하나의 엄지 손가락 규칙- "가치있는 무언가를 다루는 것보다는 가치와 표현을 가지고 일하고 변화 할 수있다"
rahulaga_dev

1
@Frax : 또한 FP는 명령형 프로그래밍에 대한 추상화라고 말할 수 있습니다. 궁극적으로 누군가가 "어떻게해야하는지"에 대해 기계에게 지시해야하기 때문입니다. 그렇다면 명령형 프로그래밍이 FP에 비해 더 낮은 수준의 제어를 갖지 않습니까?
rahulaga_dev

1
@Frax : Rahul은 기본 시스템에 더 가깝다는 의미에서 명령이 더 낮다는 점에 동의합니다. 하드웨어가 무료로 데이터 사본을 만들 수 있다면 효율성을 개선하기 위해 파괴적인 업데이트가 필요하지 않습니다. 이런 의미에서 명령형 패러다임은 금속에 더 가깝습니다.
Giorgio

9

가변 상태의 사용은 일반적으로 기능적 프로그래밍에서 권장되지 않습니다. 루프는 변경 가능한 상태와 조합해서 만 유용하기 때문에 루프는 권장하지 않습니다.

함수 전체가 순수하므로 훌륭하지만 함수 프로그래밍의 패러다임은 전체 함수 레벨에만 적용되는 것은 아닙니다. 또한 함수 내부의 로컬 수준에서도 변경 가능한 상태를 피하고 싶습니다. 그리고 추론은 기본적으로 동일합니다. 변경 가능한 상태를 피하면 코드를 이해하기 쉽고 특정 버그를 방지 할 수 있습니다.

귀하의 경우에는 numbers.Where(predicate).Sum()훨씬 간단하게 작성할 수 있습니다. 그리고 단순할수록 버그가 줄어 듭니다.


고마워 !! 필자는 눈에 띄는 라인이 누락되었다고 생각 하지만 함수형 프로그래밍의 패러다임은 전체 기능 수준에만 적용되는 것이 아니라 이제이 경계를 시각화하는 방법이 궁금합니다. 기본적으로 소비자 관점에서는 순수한 기능이지만 실제로이 기능을 작성한 개발자는 순수한 기능 지침을 따르지 않았습니까? 혼란 :(
rahulaga_dev

@RahulAgarwal : 어떤 경계?
JacquesB

프로그래밍 패러다임이 함수 소비자 관점에서 FP와 같은 자격을 갖추면 혼란 스럽습니다. Bcoz Wherein 구현 구현을 살펴보면 루프 numbers.Where(predicate).Sum()를 사용 foreach합니다.
rahulaga_dev

3
@RahulAgarwal : 함수의 소비자로서, 함수 나 모듈이 외부 적으로 순수하다면 함수 나 모듈이 내부적으로 가변 상태를 사용하는지는 신경 쓰지 않습니다.
JacquesB

7

외부 관찰자의 관점에서 Sum함수가 순수하고 내부 구현이 명확하지 않다는 것이 정확하지만 result반복적으로 변경되는 상태 가 있습니다. 더 버그 차례의 리드에 프로그래머에 더 큰인지 부하 생성하기 때문에 가변 상태를 피할 수있는 이유 중 하나는 [표창장은 필요로했다]를 .

이와 같은 간단한 예에서 저장 가능한 변경 가능 상태의 양은 심각한 문제를 일으키지 않을 정도로 작을 수 있지만 일반적인 원칙은 여전히 ​​적용됩니다. 장난감 예제는 Sum아마도 명령형에 비해 함수형 프로그래밍의 장점을 설명하는 가장 좋은 방법은 아닙니다. 변하기 쉬운 상태 로 많은 것을 시도 하면 이점이 더 명확해질 수 있습니다.

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