Math.random ()을 호출하는 함수가 순수합니까?


112

다음은 순수한 기능입니까?

function test(min,max) {
   return  Math.random() * (max - min) + min;
}

내 이해는 순수한 기능이 다음 조건을 따른다는 것입니다.

  1. 매개 변수에서 계산 된 값을 반환합니다.
  2. 반환 값을 계산하는 것 외에는 어떤 작업도하지 않습니다.

이 정의가 맞다면 내 함수가 순수한 함수입니까? 아니면 순수한 함수를 정의하는 것에 대한 나의 이해가 잘못 되었습니까?


66
"반환 값을 계산하는 것 외에는 어떤 일도하지 않습니다."그러나 Math.random()RNG의 상태를 변경하는 것을 호출합니다 .
Paul Draper

1
두 번째 요점은 "외부 (기능) 상태를 변경하지 않음"과 비슷합니다. 그리고 첫 번째는 사람들이 아래에

임의성을 허용하는 semipure 함수의 개념이 있습니까? 예를 들어 test(a,b)항상 동일한 객체를 반환 Random(a,b)합니까 (다른 구체적인 숫자를 나타낼 수 있음)? Random상징적으로 유지한다면 그것은 고전적인 의미에서 순수하고, 조기에 평가하고, 아마도 일종의 최적화로서 수치를 입력한다면, 함수는 여전히 약간의 "순수성"을 유지합니다.
JDM

1
"임의의 숫자를 생성하는 산술적 방법을 고려하는 사람은 물론 죄의 상태에 있습니다."
Steve Kuo 2017

1
@jdm "semi-pure"의 스레드를 따르면 함수가 순수 모듈로 일부 잘 정의 된 부작용 을 고려 하면 결국 모나드를 발명하게 될 수 있습니다. 어두운면에 오신 것을 환영합니다. > :)
luqui

답변:


185

아니, 그렇지 않습니다. 동일한 입력이 주어지면이 함수는 다른 값을 반환합니다. 그러면 입력과 출력을 매핑하는 '테이블'을 만들 수 없습니다.

Pure 함수에 대한 Wikipedia 기사에서 :

함수는 항상 동일한 인수 값이 주어지면 동일한 결과 값을 평가합니다. 함수 결과 값은 프로그램 실행이 진행되는 동안 또는 프로그램의 다른 실행간에 변경 될 수있는 숨겨진 정보 또는 상태에 의존 할 수 없으며 I / O 장치의 외부 입력에도 의존 할 수 없습니다.

또 다른 것은 이 스레드 에서 설명한대로 순수 함수를 입력 및 출력의 매핑을 나타내는 테이블로 대체 할 수 있다는 것입니다 .

이 함수를 다시 작성하고 순수 함수로 변경하려면 임의의 값도 인수로 전달해야합니다.

function test(random, min, max) {
   return random * (max - min) + min;
}

그런 다음 다음과 같이 호출합니다 (예 : 최소 및 최대로 2와 5 사용).

test( Math.random(), 2, 5)

2
호출하기 전에 함수 내에서 매번 랜덤 생성기를 다시 시드하면 Math.random어떨까요?
cs95

16
@ cᴏʟᴅsᴘᴇᴇᴅ 그럼에도 불구하고 여전히 부작용이 있습니다 (향후 Math.random출력 변경 ); 순수하게하려면 현재 RNG 상태를 저장하고 다시 시드하고를 호출 Math.random하고 이전 상태로 복원해야합니다.
LegionMammal978

2
@ cᴏʟᴅsᴘᴇᴇᴅ 계산 된 모든 RNG는 가짜 임의성을 기반으로합니다. 무언가가 그 아래에서 실행되어 무작위로 나타나야하며 그 원인을 설명 할 수 없어 불순합니다. 또한 질문에 더 중요한 것은 Math.random을 시드 할 수 없다는 것입니다.
zfrisch

14
@ LegionMammal978… 그리고 원자 적으로 그렇게합니다.
wchargin

2
@ cᴏʟᴅsᴘᴇᴇᴅ 순수한 함수로 작동하는 RNG를 갖는 방법이 있지만, RNG 상태를 함수로 전달하고 함수가 대체 RNG 상태를 반환하도록하는 것이 포함됩니다. 그것.
Pharap

50

귀하의 질문에 대한 간단한 대답 은 규칙 # 2Math.random()위반하는 것입니다.

여기에있는 다른 많은 답변은 존재 Math.random()가이 기능이 순수하지 않다는 것을 의미한다고 지적했습니다 . 그러나 나는 그것을 사용하는 기능을 오염시키는 이유를 말할 가치가 있다고 생각 Math.random()합니다.

모든 의사 난수 생성기와 마찬가지로 Math.random()"시드"값으로 시작합니다. 그런 다음이 값을 낮은 수준의 비트 조작 체인 또는 예측할 수없는 (실제로 무작위가 아닌 ) 출력 을 초래하는 기타 작업의 시작점으로 사용합니다 .

JavaScript에서 관련된 프로세스는 구현에 따라 다르며 다른 많은 언어와 달리 JavaScript는 시드를 선택할 수있는 방법을 제공 하지 않습니다 .

구현은 난수 생성 알고리즘에 대한 초기 시드를 선택합니다. 사용자가 선택하거나 재설정 할 수 없습니다.

이것이이 함수가 순수하지 않은 이유입니다. JavaScript는 기본적으로 사용자가 제어 할 수없는 암시 적 함수 매개 변수를 사용합니다. 다른 곳에서 계산되고 저장된 데이터에서 해당 매개 변수를 읽고 있으므로 정의의 규칙 # 2를 위반합니다.

이 함수를 순수 함수로 만들고 싶다면 여기에 설명 된 대체 난수 생성기 중 하나를 사용할 수 있습니다 . 그 발전기를 호출하십시오 seedable_random. 하나의 매개 변수 (시드)를 사용하고 "무작위"숫자를 반환합니다. 물론,이 숫자는 전혀 무작위가 아닙니다. 그것은 종자에 의해 유일하게 결정됩니다. 이것이 이것이 순수한 기능인 이유입니다. 의 출력은 seedable_random입력을 기반으로 출력을 예측하는 것이 어렵다는 의미에서 "무작위"일뿐입니다.

이 함수의 순수 버전은 세 가지 매개 변수 를 가져야합니다 .

function test(min, max, seed) {
   return  seedable_random(seed) * (max - min) + min;
}

주어진 세 개의 (min, max, seed)매개 변수에 대해 항상 동일한 결과를 반환합니다.

의 출력 seedable_random진정으로 무작위가되도록하려면 시드를 무작위 화하는 방법을 찾아야합니다! 그리고 어떤 전략을 사용하든, 기능 외부의 소스에서 정보를 수집해야하기 때문에 필연적으로 순수하지 않을 것입니다. 으로 mtraceurjpmc26 나를 생각 나게,이 모든 물리적 접근을 포함한다 : 하드웨어 난수 발생기를 , 렌즈 캡 웹캠 , 대기 소음 수집 - 심지어 용암 램프 . 이 모든 것에는 함수 외부에서 계산되고 저장된 데이터를 사용하는 것이 포함됩니다.


8
Math.random ()은 "seed"를 읽을뿐만 아니라 수정하여 다음 호출에서 다른 것을 반환합니다. 수정에 따라 정적 상태는 순수 함수에 확실히 나쁩니다.
Nate Eldredge

2
@NateEldredge, 정말! 단순히 구현에 따른 값을 읽는 것만으로도 순도를 깨기에 충분합니다. 예를 들어 Python 3 해시가 프로세스간에 어떻게 안정적이지 않은지 확인한 적이 있습니까?
senderle

2
Math.randomPRNG를 사용하지 않고 하드웨어 RNG를 사용하여 구현 한 경우이 답변이 어떻게 변경 됩니까? 하드웨어 RNG는 정상적인 의미에서 실제로 상태가 없지만 임의의 값을 생성하므로 입력에 관계없이 함수 출력이 여전히 다릅니다.
mtraceur

@mtraceur, 맞습니다. 그러나 나는 그 답이 많이 바뀔 것이라고 생각하지 않습니다. 사실, 이것이 제가 대답에서 "상태"에 대해 이야기하는 데 시간을 소비하지 않는 이유입니다. 하드웨어 RNG에서 읽는 것은 "다른 곳에서 계산되고 저장된 데이터"에서 읽는 것을 의미하기도합니다. 데이터가 환경과 상호 작용할 때 컴퓨터 자체의 물리적 매체에 계산되고 저장되기 때문입니다.
senderle

1
이 동일한 논리는 Random.org의 대기 소음 과 같은 더 정교한 무작위 화 체계에도 적용됩니다 . +1
jpmc26

38

순수 함수는 관찰 가능한 부작용없이 반환 값이 입력 값에 의해서만 결정되는 함수입니다.

Math.random을 사용하면 입력 값이 아닌 다른 값으로 값을 결정합니다. 순수한 기능이 아닙니다.

출처


25

아니요, 출력이 단지 의존하지 않기 때문에 순수한 함수가 아닙니다. 제공된 입력 (Math.random ()은 모든 값을 출력 할 수 있음) 순수 함수가 항상 동일한 입력에 대해 동일한 값을 출력해야하기 때문에 순수 함수가 아닙니다.

함수가 순수하면 동일한 입력으로 여러 호출을 최적화하고 이전 호출의 결과를 재사용하는 것이 안전합니다.

적어도 저와 다른 많은 사람들에게 PS는 redux라는 용어를 순수 함수 라는 용어로 유명 하게 만들었습니다 . redux 문서에서 바로 :

감속기 안에서 절대하지 말아야 할 것 :

  • 인수를 변경하십시오.

  • API 호출 및 라우팅 전환과 같은 부작용을 수행합니다.

  • 순수하지 않은 함수 (예 : Date.now () 또는 Math.random ())를 호출합니다.


3
다른 사람은 큰 응답을 제공하고 있지만,의 REDUX의 문서가 특별히 :) 그들에 언급 된 내 마음 인 Math.random ()에 왔을 때 나는 나 자신을 저항 할 수 있지만
Shubhnik 싱

20

수학적 관점에서 귀하의 서명은

test: <number, number> -> <number>

그러나

test: <environment, number, number> -> <environment, number>

는의 environment결과를 제공 할 수 Math.random()있습니다. 그리고 실제로 무작위 값을 생성하면 환경이 부작용으로 바뀌므로 첫 번째 환경과 같지 않은 새 환경도 반환됩니다!

즉, 초기 인수 ( <number, number>부분) 에서 나오지 않는 입력이 필요한 경우 실행 환경 (이 예에서는에 대한 상태 제공 Math) 이 제공되어야합니다 . I / O 등과 같은 다른 답변에서 언급 된 다른 것들에도 동일하게 적용됩니다.


비유로, 이것이 객체 지향 프로그래밍이 어떻게 표현 될 수 있는지 알 수 있습니다.

SomeClass something
T result = something.foo(x, y)

실제로 우리는

foo: <something: SomeClass, x: Object, y: Object> -> <SomeClass, T>

메서드가 호출 된 개체가 환경의 일부가됩니다. 그리고 왜 SomeClass결과 의 일부입니까? something의 상태도 변경되었을 수 있기 때문입니다 !


7
설상가상으로 환경도 변형 되었기 때문에 test: <environment, number, number> -> <environment, number>다음과 같아야합니다.
Bergi

1
OO 예제가 매우 유사한 지 잘 모르겠습니다. 의 유형에 따라 오버로드 된 정의로 발송하는 특수 규칙이있는 a.F(b, c)구문 설탕으로 볼 수 있습니다 (실제로 Python이 나타내는 방식입니다). 그러나 두 표기법 모두에서 여전히 명시 적이지만 순수하지 않은 함수의 환경은 소스 코드에서 언급되지 않습니다. F(a, b, c)Faa
IMSoP


10

이 함수가 결정적이지 않은 방법을 올바르게 지적하는 다른 답변 외에도 부작용이 있습니다. 향후 호출 math.random()이 다른 답변을 반환하도록합니다. 그리고 해당 속성이없는 난수 생성기는 일반적으로 OS에서 제공하는 임의 장치에서 읽는 것과 같은 일종의 I / O를 수행합니다. 둘 중 하나는 순수한 기능을위한 verboten입니다.


7

아니요, 그렇지 않습니다. 결과를 전혀 알아낼 수 없으므로이 코드는 테스트 할 수 없습니다. 해당 코드를 테스트 가능하게하려면 난수를 생성하는 구성 요소를 추출해야합니다.

function test(min, max, generator) {
  return  generator() * (max - min) + min;
}

이제 생성기를 모의하고 코드를 올바르게 테스트 할 수 있습니다.

const result = test(1, 2, () => 3);
result == 4 //always true

그리고 "프로덕션"코드에서 :

const result = test(1, 2, Math.random);

1
▲ 테스트 가능성에 대한 당신의 생각. 약간의주의를 기울이면을 수락하는 동안 반복 가능한 테스트를 생성 할 수도 있습니다 util.Random. 테스트 실행 시작시 시드하여 이전 동작을 반복하거나 새 (그러나 반복 가능한) 실행을 위해 시드 할 수 있습니다. 멀티 스레딩의 경우 메인 스레드에서이 작업을 수행하고이를 사용 Random하여 반복 가능한 스레드 로컬을 시드 할 수 있습니다 Random. 그러나 내가 이해하는 test(int,int,Random)바와 같이 Random.
PJTraill

2

다음 사항이 괜찮을까요?

return ("" + test(0,1)) + test(0,1);

동등하다

var temp = test(0, 1);
return ("" + temp) + temp;

?

보시다시피 pure의 정의는 입력 값 외에는 출력이 변경되지 않는 함수입니다. JavaScript가 함수에 순수 태그를 지정하고이를 활용하는 방법이 있다고 말하면 최적화 프로그램은 첫 번째 표현식을 두 번째 표현식으로 다시 작성할 수 있습니다.

나는 이것에 대한 실제 경험이 있습니다. SQL 서버 는 "순수한"기능을 허용 getdate()하고 newid()옵티마이 저는 원하는대로 호출을 중복 제거합니다. 때때로 이것은 멍청한 일을 할 것입니다.

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