프로그래머에게 참조 투명성의 이점은 무엇입니까?


18

프로그래밍에서 참조 투명성 의 이점은 무엇 입니까?

RT는 기능적 패러다임과 명령형 패러다임의 주요 차이점 중 하나를 만들고, 기능적 패러다임을지지하는 사람들이 종종 명령형 패러다임에 대한 명확한 이점으로 사용합니다. 그러나 그들의 모든 노력에서,이 옹호자들은 왜 그것이 프로그래머로서 나에게 이익이되는지 설명하지 않습니다 .

물론, "순수"와 "우아함"에 대한 학문적 인 설명이 있지만 덜 "순수한"코드보다 더 나은 방법은 무엇입니까? 일상적인 프로그래밍에서 어떤 이점이 있습니까?

참고 : 이것은 참조 투명성이란 무엇입니까? 후자 는 RT 가 무엇인지에 대한 주제를 다루고 있지만이 질문은 그 이점을 다루고 있습니다 (이 직관적이지 않을 수도 있음).




3
참조 투명도는 방정식 추론 을 사용 하여 1) 코드의 속성을 증명하고 2) 프로그램을 작성할 수 있습니다. Haskell에 관한 몇 권의 책이 있습니다. 저자는 함수를 완전히 채우기 위해 원하는 방정식에서 시작하여 방정식 추론을 사용하여 해당 함수의 구현을 얻습니다. 그러므로 확실히 맞습니다. 이제 이것이 "하루에"프로그래밍에 얼마나 적용될 수 있는지는 아마도 상황에 달려있을 것입니다.
Bakuriu

2
@err 함수를 두 번 호출하는 것이 변수에 값을 저장 한 다음 해당 변수를 두 번 사용하는 것과 같은지 알기 때문에 리팩토링하기 쉬운 코드를 좋아합니까? 이것이 일상 프로그래밍에 도움이된다고 말할 수 있습니까?
Andres F.

이점은 참조 비 투명성에 대해 생각하는 데 시간을 낭비 할 필요가 없다는 것입니다. 변수의 이점이 레지스터 할당에 대해 생각하는 데 시간을 낭비 할 필요가 없다는 점을 좋아합니다.
user253751

답변:


37

장점은 순수한 함수로 코드를 쉽게 추론 할 수 있다는 것입니다. 즉, 부작용으로 인해 코드의 복잡성이 증가합니다.

computeProductPrice방법 의 예를 들어보십시오 .

순수한 방법은 제품 수량, 통화 등을 요구할 것입니다. 동일한 인수로 메소드가 호출 될 때마다 항상 동일한 결과를 생성 한다는 것을 알고 있습니다.

  • 캐시하고 캐시 된 버전을 사용할 수도 있습니다.
  • 값이 변경되지 않는다는 것을 알고 실제로 필요할 때 호출을 지연시키고 호출을 연기 할 수 있습니다.
  • 부작용이 없음을 알고 메소드를 여러 번 호출 할 수 있습니다.
  • 필요한 모든 것이 인수라는 것을 알면 메소드 자체를 세상과 분리하여 추론 할 수 있습니다.

순수하지 않은 방법은 사용 및 디버그가 더 복잡합니다. 인수 이외의 변수 상태에 따라 변경 될 수 있으므로 여러 번 호출 할 때 다른 결과를 생성하거나 전혀 호출하지 않거나 너무 빨리 또는 너무 늦게 호출 될 때 동일한 동작을하지 않을 수 있음을 의미합니다.

프레임 워크에 숫자를 구문 분석하는 방법이 있다고 상상해보십시오.

decimal math.parse(string t)

다음에 의존하기 때문에 참조 투명성이 없습니다.

  • 번호 매기기 시스템, 즉 Base 10 등을 지정하는 환경 변수입니다.

  • math구문 분석 할 숫자의 정밀도를 지정 하는 라이브러리 내의 변수 입니다. 따라서 값을 사용 1하면 문자열 "12.3456"을 구문 분석하면 됩니다 12.3.

  • 예상되는 형식을 정의하는 문화권. 예를 들어,와 fr-FR, 구문 분석 "12.345"줄 것이다 12345분리 문자가해야하기 때문에 ,,하지.

그러한 방법으로 작업하는 것이 얼마나 쉬운 지 상상해보십시오. 동일한 입력을 사용하면 메서드를 호출하는 순간에 따라 환경 변수가 변경되거나 문화권이 바뀌거나 다른 정밀도가 설정되므로 결과가 크게 달라질 수 있습니다. 이 방법의 비 결정적 특성은 더 많은 버그와 더 많은 악몽을 초래할 것입니다. 일부 병렬 코드가 8 진수를 구문 분석했기 때문에 전화를 걸고 답변을 math.parse("12345")얻는 5349것은 좋지 않습니다.

이 깨진 방법을 고치는 방법? 참조 투명성을 도입함으로써. 다시 말해, 전역 상태를 제거하고 모든 것을 메소드의 매개 변수로 옮김으로써 :

decimal math.parse(string t, base=10, precision=20, culture=cultures.en_us)

이제 메소드가 순수하므로 메소드를 호출 할 때마다 동일한 인수에 대해 항상 동일한 결과를 생성한다는 것을 알고 있습니다.


4
부록 : 참조 투명성은 함수뿐만 아니라 언어의 모든 표현에 적용됩니다.
gardenhead

3
투명도에는 제한이 있습니다. packet = socket.recv()참조 적으로 투명하게 만들면 기능의 요점이 무너집니다.
Mark

1
culture = cultures.invariant 여야합니다. 당신이하지 않으면 원하는 실수로 미국에서만 제대로 작동 소프트웨어를 만들 수 있습니다.
user253751

@immibis : 흠, 좋은 질문입니다. 파싱 ​​규칙은 invariant무엇입니까? 이 경우와 동일합니다 en_us.이 경우 왜 귀찮거나 다른 국가에 해당합니다.이 경우 대신이 국가와 다른 국가에 해당 en_us하거나 특정 국가와 일치하지 않는 특정 규칙이 있습니다. 쓸모없는 것입니다. 12,345.67와 사이에는 "정답"이 없습니다 12 345,67. "기본 규칙"은 일부 국가에서는 작동하지만 다른 국가에서는 작동하지 않습니다.
Arseni Mourzenko

3
@ArseniMourzenko 일반적으로 "가장 낮은 공통 분모"이며 많은 프로그래밍 언어에서 사용하는 구문과 유사합니다 (배양 불변). 1234512345로 파싱 12 345하거나 12,345또는 12.345에러이다. 12.345고정 부동 소수점 수로 구문 분석하면의 프로그래밍 언어 규칙에 따라 항상 12.345가 생성됩니다. 소수점 구분 기호로. 문자열은 유니 코드 코드 포인트에 따라 대소 문자를 구분하여 정렬됩니다. 등등.
user253751 2018

11

코드에서 특정 지점에 중단 점을 추가하고 발생하는 문제를 해결하기 위해 디버거에서 앱을 실행합니까? 그렇다면 디자인에서 참조 투명도 (RT)를 사용하지 않기 때문입니다. 따라서 코드를 실행하여 기능을 수행해야합니다.

RT에 대한 요점은 코드가 결정 론적이라는 것입니다. 즉, 동일한 입력 세트에 대해 코드를 읽고 매번 수행하는 작업을 수행 할 수 있습니다. 변이 변수를 추가하기 시작하면 일부 변수가 단일 함수를 넘어 범위를 가지면 코드를 읽을 수 없습니다. 이러한 코드는 실제로 작동하는 방식을 해결하기 위해 헤드 또는 디버거에서 실행되어야합니다.

코드를 읽고 추론하는 것이 더 간단하고 버그를 유지하고 발견하는 것이 더 간단하므로 귀하와 고용주의 시간과 비용을 절약 할 수 있습니다.


10
"단일 함수를 넘어서서 돌연변이 변수를 추가하기 시작하면 코드를 읽을 수없고, 머리 나 디버거에서 코드를 실행하여 실제로 작동하는 방식을 찾아야합니다. ": 좋은 지적. 즉, 참조 투명성은 코드 조각이 항상 동일한 입력에 대해 동일한 결과를 생성 할뿐 아니라 생성 된 결과가 해당 코드 조각의 유일한 효과이며 숨겨진 다른면이 없음을 의미합니다. 다른 모듈에서 멀리 정의 된 변수를 변경하는 것과 같은 효과.
Giorgio

좋은 지적입니다. 나는 상기와 약간의 문제가 어떻게 코드를 읽을 수있는 간단한 / 이유 때문에 인수를 읽거나 이유는 더 간단 코드의 다소 모호하고 주관적 속성입니다.
Eyal Roth

변이 변수를 추가하기 시작하면 일부 함수가 단일 함수를 넘어 범위를 가지지 만 변수 범위가 함수에 대해 로컬 인 경우에도 할당 작업이 권장되지 않는 이유는 무엇입니까?
rahulaga_dev

9

사람들은 "추론하기 쉬운"이라는 용어를 던지지 만 그 의미를 설명하지는 않습니다. 다음 예를 고려하십시오.

result1 = foo("bar", 12)
// 100 lines of code
result2 = foo("bar", 12)

인가 result1result2동일하거나 다른? 참조 투명성이 없다면, 당신은 모른다. 실제로 본문을 읽고 foo함수 foo호출 의 본문 등 을 확인해야 합니다.

사람들은 그들이 그것에 익숙해 있기 때문에이 부담을 알 수 있지만, 한두 달에 대한 순수하게 기능적인 환경에서 일을 가면 그때 당신은 그것을 느낄 것입니다 돌아오고, 그것이하지 않는 큰 거래 .

참조 투명성 부족을 해결하기 위해 사람들이 수행하는 많은 방어 메커니즘이 있습니다. 내 작은 예를 들어, 나는 result1그것이 변화하는지 알지 못하기 때문에 메모리 에 보관하고 싶을 수도 있습니다. 그런 다음 두 가지 상태의 코드가 있습니다. 전과 result1저장 후. 참조 투명성을 사용하면 재 계산에 시간이 걸리지 않는 한 쉽게 재 계산할 수 있습니다.


1
당신은 그 참조 투명성 foo에 대한 호출 ()의 결과에 대한 이유에 당신을 허용하고 있는지 알고 언급 result1result2동일합니다. 또 다른 중요한 측면은 foo("bar", 12)참조가 투명 하다면 ,이 호출이 다른 곳에서 어떤 영향을 미쳤는지 스스로에게 묻지 않아도된다는 것입니다 (일부 변수 설정? 파일 삭제? 무엇이든).
Giorgio

내가 아는 유일한 "참조 무결성"은 관계형 데이터베이스와 관련이 있습니다.
Mark

1
@Mark 오타입니다. Karl은 그의 나머지 답변에서 알 수 있듯이 참조 투명성을 의미했습니다.
Andres F.

6

나는 말할 것입니다 : 참조 투명성은 함수형 프로그래밍뿐만 아니라 함수를 다루는 모든 사람들에게 가장 놀랍습니다.

고려해야 할 외부 요소가 없기 때문에 함수가 있고 그 기능에 대해 더 잘 추론 할 수 있습니다. 주어진 입력에 대해 출력이 항상 동일합니다. 제 명령 언어에서도 가능한 한이 패러다임을 따르려고 노력합니다. 기본적으로 다음과 같이 자동으로 따르는 것은 다음과 같습니다. 때때로 실행되는 끔찍한 1000 + 라인 함수 대신 이해하기 쉬운 작은 함수입니다.

이 큰 기능들은 마술처럼 작용하며 그것들이 환상적인 방식으로 깨질 수 있기 때문에 그것들을 만질 것을 두려워합니다.

따라서 순수한 함수는 함수형 프로그래밍뿐만 아니라 모든 프로그램을위한 것입니다.

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