"부작용"이란 무엇입니까?


87

부작용의 개념을 명확하게 이해하지 못했습니다.

  • 프로그래밍의 부작용은 무엇입니까?
  • 프로그래밍 언어에 의존합니까?
  • 외부 및 내부 부작용과 같은 것이 있습니까?

부작용을 일으키는 원인의 예를 제시하십시오.


7
숙제와 매우 흡사합니다.
gnasher729

3
이 문제에 관심이있는 @ gnasher729는 TREMENDOUSLY 유용합니다 :)
Charlie Parker

답변:


108

부작용은 국가의 어떤 종류의 수정 단순히 의미 - 예를 들면 :

  • 변수 값 변경
  • 디스크에 일부 데이터 쓰기;
  • 사용자 인터페이스에서 버튼 활성화 또는 비활성화

일부 사람들의 말과 달리 :

  • 부작용 않습니다 하지 숨길 수 또는 예상치 못한이 (가 될 수 있지만 그것이 컴퓨터 과학에 적용되는 정의와는 아무 상관이 없습니다)

  • 부작용은 dem 등원과 관련없습니다 . dem 등원 기능에는 부작용이있을 수 있으며 비등 전성 기능에는 부작용이 없을 수 있습니다 (예 : 현재 시스템 날짜 및 시간 가져 오기).

정말 간단합니다. 부작용 = 어딘가에 무언가를 바꾸는 것.

PS 주석가 벤졸이 지적한 바와 같이, 몇몇 사람들은 부작용 정의를 순수한 기능 의 정의 와 (a) dem 등원 및 (b) 부작용이없는 기능인 것과 동일시 할 수있다 . 하나는 일반적인 컴퓨터 과학에서 다른 하나를 의미하지는 않지만 기능적 프로그래밍 언어는 일반적으로 두 가지 제약 조건을 모두 적용하는 경향이 있습니다.


38
"부작용"이라는 문구 는 의도 한 것 이외의 다른 것이 바뀌는 것처럼 들립니다 . 의학에서 약물은 통증을 줄이는 주요 효과가 있으며 때로는 코 출혈, 현기증 등의 부작용이 있습니다. 약물의 목적은 코 출혈을 유발하는 것이 아니라 때로는 의도하지 않은 추가 결과.
FrustratedWithFormsDesigner

15
@ 좌절 : +1. 그 용어를 볼 때마다 나는 FP 옹호자들이 그 미묘한 불길한 함의를 정확하게 만들어 내기 위해 그것을 선택하지 않았는지 궁금해 할 수밖에 없습니다.
메이슨 휠러

6
@Mason Wheeler. FP 이전에 존재했습니다. 그리고 그것은 미묘하게 불길한 의미가 아닙니다. 그것은 평범한 악이며 항상 그렇습니다. 제가 30 년 동안 코딩해온 결과, "암호화 할당"정책 (부수 효과)은 사람들을 괴롭 혔습니다. 평범한 오래된 과제 진술에 대처하는 것이 훨씬 쉽습니다.
S.Lott

7
@Mason Wheeler : C에서 ++a. 과제처럼 보이지 않습니다. b = ++a;두 가지 부작용이 있습니다. 명백한 것과의 암호 할당 a. 그것은 (일부에게는) 바람직한 부작용입니다. 그러나 내 경력 전체가 미묘하지 않게 부작용으로 불렸다.
S.Lott

5
@ Zachary, 내 대답의 마지막 글 머리 기호를 참조하십시오. 당신이 말하는 것은 dem 등식 행동 (또는 그것의 부족)입니다. 부작용에 대해서는 아무 것도 알려주지 않습니다. 시스템 시계를 확인하는 것은 부작용 이 아닙니다 . 실제로 "get"이라는 접두사가 붙은 함수 나 메소드는 부작용이없는 것으로 합리적으로 기대해야합니다.
Aaronaught

36

컴퓨터의 상태를 수정하거나 외부 세계와 상호 작용하는 모든 작업은 부작용이 있다고합니다. 부작용 에 대한 Wikipedia를 참조하십시오 .

예를 들어이 기능에는 부작용이 없습니다. 결과는 입력 인수에만 의존하며 프로그램 상태 또는 호출 될 때 환경이 변경되지는 않습니다.

int square(int x) { return x * x; }

반대로,이 함수를 호출하면 컴퓨터 상태에 따라 변경되기 때문에 호출 순서에 따라 다른 결과를 얻을 수 있습니다.

int n = 0;
int next_n() { return n++; }
void set_n(int newN) { n = newN; }      

이 함수는 출력에 데이터를 쓰는 부작용이 있습니다. 반환 값을 원하기 때문에 함수를 호출하지 않습니다. "외부 세계"에 미치는 영향을 원하기 때문에이를 호출합니다.

int Write(const char* s) { return printf("Output: %s\n", s); }

1
이것은 좋은 정의이지만, 정교함에 대해서는 미치지 않습니다. Thorbjørn의 답변에서와 같이 부작용의 문제는 pot 등식 기능의 문제와 관련이있는 것으로 보입니다. AS를 Write예를 보여 부작용을 갖는 함수 적 출력이 모든 입력에 따라 심지어는 그 입력에 대하여 출력을 변경하거나하는 것을 의미하지는 않는다.
Aaronaught

6
dem 등성이 아닙니다. 출력을 생성한다는 사실은 부작용이 있음을 의미합니다.
Kristopher Johnson

일부 시스템에서 호출 square(x)하면 함수가 정의 된 모듈이 디스크에서로드 될 수 있습니다. 이것이 부작용으로 간주되어야합니까? 결국, 이것은 (첫번째) 호출이 예기치 않게 오래 걸리고, RAM 사용량이 증가하는 등을 언급합니다.
Hagen von Eitzen

1
@HagenvonEitzen 모든 작업은 실제로 컴퓨터 상태 (CPU 레지스터, 메모리, 전력 소비, 열 등)를 변경합니다. "부작용"은 일반적으로 프로그램이 명시 적으로 변경하지 않는 한 해당 환경에 대해 아무것도 변경되지 않는 가상의 이상적인 실행 환경을 말합니다. 당신이 호출하지만 square(x) 때문에 외부 컴퓨터 상태를 변경하는 것을 원하는, 당신은 그 부작용으로 고려할 수 있습니다.
Kristopher Johnson

저에게는 첫 번째 그림이 완벽합니다. 그러나 두 번째는 그렇지 않습니다. 부작용은 특정 환경 / 범위와 관련하여 정의되어야한다고 생각합니다. 전체 우주를 고려한다면 부작용이없는 것은 없습니다. 컴퓨터로 제한하더라도 CPU가 동일하게 작동하지 않는 기능은 다른 프로세스에 영향을 미칩니다. 범위를 로컬 함수 범위에서 액세스 가능한 것으로 제한하면 우리가 이야기 할 것이 있습니다.
funct7

20

기존 답변이 상당히 좋다고 생각합니다. IMO에 스트레스가 충분하지 않은 몇 가지 측면을 자세히 설명하고 싶습니다.

수학에서 함수는 튜플 값에서 값으로의 매핑입니다. 그래서, 함수 주어진 f과 값 x, f(x)항상 같은 결과가 될 것입니다 y. 당신은 잘 대체 할 수 f(x)y식 도처에서 아무것도 변경됩니다.

많은 프로그래밍 언어에서 함수 (또는 프로 시저)는 다음과 같은 이유로 실행될 수있는 구성 (코드 조각)입니다.

  1. 수학적 의미로 함수를 계산합니다. 즉, 주어진 입력 값, 결과를 반환합니다. 또는
  2. 예를 들어 화면에 무언가를 인쇄하고, 데이터베이스의 값을 변경하고, 미사일을 발사하고, 10 초 동안 잠을 자고, SMS를 보내는 등의 효과가 있습니다.

따라서 효과는 상태뿐만 아니라 미사일 발사 또는 몇 초 동안 실행 일시 중지와 같은 다른 측면과 관련 될 수 있습니다.

부작용이라는 용어는 부정적으로 들릴 수 있지만 일반적으로 함수 호출의 효과는 함수 자체의 목적입니다. I 용어 함수 원래 수학에서 사용 된 이후의 값을 계산하는 것은로 간주한다는 가정 차 효과 다른 영향이 고려되는 반면 함수의 부작용 . 일부 프로그래밍 언어는 프로 시저 라는 용어를 사용 하여 수학적인 의미에서 함수와 혼동을 피합니다.

참고

  1. 일부 절차는 반환 값과 부작용에 모두 유용합니다.
  2. 일부 프로시 저는 결과 값만 계산하며 다른 효과는 없습니다. 수학 함수에서 함수를 계산하기 만하면되기 때문에 종종 순수 함수라고합니다.
  3. sleep()파이썬 과 같은 일부 절차 는 부작용에 대해서만 유용합니다. 이것들은 종종 특별한 값을 반환하는 함수로 모델링 None되거나 unit또는 ()또는 ... 또는 단순히 계산이 올바르게 종료되었음을 나타내는 함수로 모델링 됩니다.

2
나의 겸손한 견해로는 이것이 받아 들여질만한 대답이어야한다. 부작용의 개념은 수학 함수의 관점에서만 의미가 있습니다. 절차는 단순히 일련의 명령어를 구조화 된 방식으로 그룹화하고 어디서나 편리하게 해당 세트로 이동할 수 있도록 설계되었습니다. 기본 의도 된 효과와 부작용은 없습니다. 예외를 던지는 것이 프로 시저의 부작용이라고 말할 수 있습니다. 프로 시저의 의도를 깨뜨려 서 중단 된 부분으로 돌아가서 실행 양식을 계속하는 것입니다.
Didier A.

4

부작용은 작업이 의도 된 용도를 벗어난 변수 / 객체에 영향을 미치는 경우입니다.

전역 변수를 변경하는 부작용이있는 복잡한 함수를 호출하면 호출 한 이유가 아니더라도 데이터베이스에서 무언가를 추출하기 위해 호출했을 수 있습니다.

나는 완전히 고안되지 않은 간단한 예제를 생각해내는 데 어려움을 겪고 있으며, 내가 작업 한 것들의 예제는 여기에 게시하기에는 너무 길다 (그리고 관련 작업이므로 어쨌든해서는 안된다) ).

내가 본 한 예는 (연결이 닫힌 상태 인 경우) 데이터베이스 연결을 여는 기능이었습니다. 문제는 함수의 끝에서 연결을 닫아야한다는 것이었지만 개발자는 해당 코드를 추가하는 것을 잊었습니다. 따라서 여기에는 의도하지 않은 부작용 이있었습니다 . 프로 시저를 호출하면 쿼리 만 수행해야하고 부작용은 연결이 열린 상태로 유지되고 함수가 두 번 연속 호출되면 연결이 발생했다는 오류가 발생합니다. 이미 열려 있습니다.


자, 이제 모두가 예제를 제공하기 때문에 나도 그렇게 할 것이라고 생각합니다.)

/*code is PL/SQL-styled pseudo-code because that's what's on my mind right now*/

g_some_global int := 0; --define a globally accessible variable somewhere.

function do_task_x(in_a in number) is
begin
    b := calculate_magic(in_a);
    if b mod 2 == 0 then
        g_some_global := g_some_global + b;
    end if;
    return (b * 2.3);
end;

함수 do_task_x갖는 일차 일부 계산의 결과를 반환하는 효과, 및 측면 가능한 글로벌 변수를 수정하는 효과.

물론, 이는 기본이고 부작용이 해석이있을 수 있고 실제 사용에 의존 수이다. 전역을 수정하기 위해이 함수를 호출하고 전역을 수정하는 것이 기본 효과 라고 말한 것보다 반환 된 값을 무시하면 됩니다.


2
나는 이것이 좋은 보편적 정의라고 생각하지 않습니다. 많은 프로그래머들이 의도적으로 부작용에 대한 구조를 사용합니다.
CB Bailey

@ 찰스 : 충분합니다. 이 경우 어떻게 정의 하시겠습니까?
FrustratedWithFormsDesigner

2
@KristopherJohnson이 가장 명확한 정의를 가지고 있다고 생각합니다. 프로그램 또는 환경의 상태를 변경하거나 출력 생성과 같은 실제 효과를 생성하는 모든 것.
CB Bailey

@Charles Bailey : 정의를 바꾸지 않습니다. 부작용으로 물건을 사용하는 것이 좋습니다. 부작용이 있다는 것을 이해하는 한. 이 정의에 대해서는 아무 것도 변경하지 않습니다.
S.Lott

1
@SLott :이 답변의 정의 (즉, 첫 번째 단락)에는 "예상 용도 이외의"절이 포함됩니다. 제 의견은 공정하다고 생각합니다.
CB Bailey

3

컴퓨터 과학에서, 함수 또는 표현은 어떤 상태를 수정하거나 호출 함수 또는 외부 세계와 관찰 가능한 상호 작용을 갖는 경우 부작용이 있다고합니다.

에서 위키 백과 - 부작용

수학적 의미에서 함수는 입력에서 출력으로의 매핑입니다. 함수 호출의 의도 된 효과는 입력을 리턴하는 출력에 맵핑하는 것입니다. 함수가 다른 작업을 수행하는 경우 문제가되지 않지만 입력에 출력을 매핑하지 않는 동작이 있으면 해당 동작이 부작용으로 알려져 있습니다.

보다 일반적인 용어로, 부작용은 구조물 설계자의 의도 된 효과가 아닌 임의의 효과이다.

효과는 배우에게 영향을 미치는 모든 것입니다. 여자 친구에게 이별 문자 메시지를 보내는 함수를 호출하면 많은 배우, 나, 그녀, 휴대 전화 회사의 네트워크 등에 영향을 미칩니다. 부작용이없는 함수를 호출하는 유일한 의도 된 효과는 함수입니다. 입력에서 매핑을 반환합니다. 그래서 :

   public void SendBreakupTextMessage() {
        Messaging.send("I'm breaking up with you!")
   }

이것이 함수로 의도 된 경우, 그것이해야 할 유일한 일은 void를 반환합니다. 부작용이없는 경우 실제로 문자 메시지를 보내지 않아야합니다.

대부분의 프로그래밍 언어에는 수학 함수를위한 구성이 없습니다. 그와 같은 구조는 사용되지 않습니다. 그렇기 때문에 대부분의 언어에는 방법이나 절차가 있다고 말합니다. 의도적으로 더 많은 효과를 낼 수 있도록 고안되었습니다. 일반적인 프로그래밍 용어에서, 아무도 메서드 나 프로 시저가 무엇인지 의도하지 않습니다. 누군가 누군가이 함수에 부작용이 있다고 말하면,이 구문은 수학 함수처럼 동작하지 않습니다. 그리고 누군가이 기능이 부작용이 없다고 말하면,이 구성은 수학 함수처럼 효과적으로 행동합니다.

순수한 기능은 정의에 따라 항상 부작용이 없습니다. 순수한 함수는 말할 수있는 방법입니다.이 함수는 더 많은 효과를 허용하는 구문을 사용하더라도 수학 함수와 동일한 효과 만 갖습니다.

부작용이없는 기능이 순수하지 않을 때는 누구에게나 알려주십시오. 순수 및 부작용이없는 용어를 사용하여 문장의 문맥에서 의도 된 주요 효과가 함수의 수학적 의도 된 효과가 아닌 경우, 그것들은 항상 동일합니다.

따라서 때로는 더 드물기는하지만 이것이 받아 들여진 대답에 사람들이 부족하고 오해하는 구별입니다 (가장 일반적인 가정이 아니기 때문에) 프로그래밍 기능의 의도 된 효과는 다음과 같습니다. 입력을 출력에 맵핑하기 위해 입력이 함수의 명시 적 매개 변수로 제한되지 않지만 출력이 명시 적 리턴 값으로 제한됩니다. 이것이 의도 된 효과라고 가정하면, 의도 한 효과의 다른 위치에서 입력을 허용했기 때문에 파일을 읽고 파일의 내용에 따라 다른 결과를 반환하는 함수는 여전히 부작용이 없습니다.

왜 이것이 중요한가?

그것은 통제와 유지에 관한 것입니다. 함수를 호출하고 다른 작업을 수행 한 다음 값을 반환하면 해당 동작을 추론하기가 어렵습니다. 실제 코드가 함수의 내부를 살펴보고 실제 코드가 수행중인 작업을 추측하고 정확성을 주장해야합니다. 이상적인 상황은 함수가 사용하는 입력이 무엇인지 알기 쉽고, 다른 작업을 수행하지 않고 출력을 반환한다는 것입니다. 이것을 조금 긴장을 풀고 사용중인 입력을 정확히 아는 것이 값을 반환하는 것을 알지 못하는 다른 일을하지 않는 것만 큼 도움이되지 않는다고 말하면 강제로 만족할 수 있습니다. 다른 작업을 수행하지 않고 입력을 가져 오는 위치에 관계없이 입력을 출력에 매핑합니다.

거의 모든 경우에있어서, 프로그램의 요점은 들어오는 것들에 매핑되는 것 이외의 다른 영향을 미치는 것입니다. 부작용을 제어하는 ​​아이디어는 이해하기 쉽고 이해하기 쉬운 방식으로 코드를 구성 할 수 있다는 것입니다. 모든 부작용을 매우 명확하고 중심적인 장소에 모아두면 더 이상 일어나지 않는 곳이 어디인지보고 신뢰할 수 있습니다. 입력이 너무 명시 적이라면 다른 입력에 대한 동작을 테스트하는 데 도움이되며 사용하기 쉽습니다. 많은 다른 장소에서 입력을 변경할 필요가 없기 때문에 일부는 명확하지 않을 수 있습니다. 원하는 것을 얻을 수 있습니다.

프로그램의 행동을 이해하고, 추론하고 통제하는 데 가장 도움이되는 것은 모든 입력을 명확하게 그룹화하고 명시 적으로 분류하는 것뿐만 아니라 모든 부작용을 함께 그룹화하고 명시 적으로 표현하는 것이기 때문에, 일반적으로 사람들이 말할 때 부작용, 순수한 등

가장 도움이되는 것은 부작용의 그룹화와 그들의 명백 함입니다. 때로는 사람들은 그 의미를 의미하고 순수한 것이 아니라 여전히 "부작용"이라고 말함으로써 구별 할 것입니다. 그러나 부작용은 "의도 된 1 차 효과"와 관련이 있으므로 문맥 상 용어입니다. 놀랍게도이 스레드에서 많은 이야기를하지만, 내가 찾은 것은 덜 자주 사용됩니다.

마지막으로, dem 등원 (Idempotent)은 동일한 입력으로이 기능을 여러 번 호출하는 것을 의미합니다 (어느 곳에서 왔든 상관없이) 항상 동일한 효과 (부작용 여부)를 초래합니다.


부작용을 설명하는 데 큰 문제는 Ocaml 또는 Haskell과 같은 언어를 사용할 때까지 부작용이없는 (거의!) 프로그래밍에 대해 추론하기가 매우 어렵다는 것입니다.
Jamie Strauss

2

프로그래밍에서 부작용은 프로 시저가 범위 밖에서 변수를 변경하는 경우입니다. 부작용은 언어에 의존하지 않습니다. 부작용 (순수한 기능성 언어)을 제거하려는 일부 언어 클래스가 있지만 부작용이 필요한 언어가 있는지 확실하지 않지만 잘못되었을 수 있습니다.

내가 아는 한 내부 및 외부 부작용은 없습니다.


더 정확하게 말하면, 순수 기능 언어는 부작용이없는 코드를 다른 코드와 명확하게 분리하는 반면, 다른 언어는 순수 코드와 불순 코드를 구별하는 메커니즘이 없습니다. 대부분의 프로그램은 사용하기 위해 부작용이 필요합니다.
Giorgio

MS-BASIC 및 QBasic과 같은 일부 사전 GUI 프로그래밍 언어는 가능한 한 '부작용 만'언어에 가깝다고 생각합니다. 그리고 네, 당신은 내부 및 외부 부작용을 모두 가질 수 있습니다.
James K

0

다음은 간단한 예입니다.

int _totalWrites;
void Write(string message)
{
    // Invoking this function has the side effect of 
    // incrementing the value of _totalWrites.
    _totalWrites++;
    Debug.Write(message);
}

부작용의 정의는 프로그래밍에만 국한된 것이 아니므로 단순히 약물의 부작용이나 음식을 너무 많이 섭취하는 것을 상상해보십시오.


그러나 메시지가 참조로 들어오고 메소드에서 메시지를 변경하면 부작용이 될 수 있습니다. 제가 맞습니까?
Amir Rezaei

표현식 x++이 변수를 수정 한다는 사실 x은 일반적으로 부작용으로 간주됩니다. 표현식의 해당 값은 x; 의 사전 증분 값입니다 . 이것은 표현의 부작용이 아닌 부분입니다.
CB Bailey

@Charles-원래 예제는 현재 예제와 같이 명확하지 않지만 동의합니다.
ChaosPandion

@Amir-글쎄, 그건 언어에 따라 다릅니다. 이것이 C #이면 부작용으로 간주되지 않습니다.
ChaosPandion

@ ChaosPandion : 개인적으로 동의하지 않습니다. 원래 예제는 훨씬 간단하고 명확했습니다.
CB Bailey

-2

부작용은 명백하지 않은 코드에서 발생하는 것입니다.

예를 들어이 클래스가 있다고 가정 해 봅시다.

public class ContrivedRandomGenerator {
   public int Seed { get; set; }

   public int GetRandomValue()
   {
      Random(Seed);
      Seed++;
   }
}

처음 수업을 만들면 씨앗을줍니다.

var randomGenerator = new ContrivedRandomGenerator();
randomGenerator.Seed = 15;
randomGenerator.GetRandomValue();

내부를 모르고 임의의 값을 얻을 것으로 예상하고 randomGenerator.Seed가 여전히 15 일 것으로 예상하지만 그렇지 않습니다.

함수 호출은 Seed 값을 변경하는 부작용이있었습니다.


10
부작용을 숨길 필요는 없습니다. 구어체 또는 의료용을 생각하고 있습니다. 프로그래밍에서 부작용은 단순히 일부 상태를 수정하는 것을 말합니다.
Aaronaught

1
콘솔에 인쇄하는 것은 부작용입니다. 숨겨져 있지 않습니다. 에서 위키 백과 : "컴퓨터 과학에서, 함수 나 표현식은 값을 반환뿐만 아니라, 또한 어떤 상태를 변경하거나 가지고있는 경우 부작용을 가지고 있다고 호출 기능이나와 관찰의 상호 작용 외부 세계를 ."

부작용은 비 기능 (즉, 절차)이 어떤 작업을 수행하는 방식입니다. X = 1; X = Y (10)은 두 가지 순수한 함수입니다. "x = whatever"영역을 벗어나면 화면에 프린터에 출력을 쓰거나 "x = y"형식 외부에서 입력을 읽거나 변수의 값을 한 항목에서 다른 항목으로 변경하는지 여부 부작용입니다.
James K

나는 '숨겨진'이라는 말은 명백하지 않은 것을 의미합니다. x = f (y, z)에서와 같이 x는 y와 z를 기반으로하는 것으로 가정 할 수 있습니다. proc (x, y, z)는 무슨 일이 일어나고 있는지 전혀 알려주지 않습니다. 모든 변수는 변경 될 수 있습니다. Proc는 f와 유사하거나 완전히 관련이 없을 수 있습니다. 순수한 함수에는 'x'라는 단일 답변이 있습니다. 그 이상으로 부작용이 있습니다. 전체적으로 의도되었지만 부작용.
James K

0을 이해하는 것처럼 먼저 1을 이해해야합니다. 부작용을 이해하려면 먼저 기능을 이해해야합니다.
James K
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.