println이 불순한 기능으로 간주되는 이유는 무엇입니까?


10

스칼라에서 책 프로그래밍을 읽고 있는데 다음과 같습니다.

...이 경우 부작용은 표준 출력 스트림으로 인쇄됩니다.

같은 입력,에 println은 동일한 출력 (내가 생각하는) 인쇄됩니다 이후, 부작용이다 나는 표시되지 않습니다
UPDATE
예를 들어 우리가 전화를 언제든지 :

println(5)

그것은 인쇄 할 5 내가 요구하는 경우 표시되지 않습니다, println(5)5 이외의 값을 출력됩니다!


이것이 귀하의 질문에 대한 답변이면, 답변을 삭제하겠습니다. softwareengineering.stackexchange.com/q/40297/271736
joelb

3
에서 답변 참조 투명성은 무엇인가? 여기에 관련이있는 것 같습니다.
Nathan Hughes


2
결정 론적으로 부작용 (참조 투명하지 않음)을 혼동했습니다. println결정적 함수이지만 순수하기 위해서는 RT 여야합니다.

2
결과를 계산하고 반환하는 것 이외의 작업을 수행하기 때문입니다.
Seth Tisue

답변:


6

표현식을 결과로 바꾸면 표현식에 부작용이 있는지 알 수 있습니다. 프로그램의 의미 가 변경되면 부작용이 있습니다. 예를 들어

println(5)

다른 프로그램입니다

()

즉, 부작용은 표현식을 평가 한 결과로 인코딩되지 않은 관찰 가능한 효과입니다. 결과는입니다 만 (), 화면에 어딘가에 5가 나타났음을 나타내는 값에는 아무것도 없습니다.


6
실제로 이것은 "부작용"에 대한 좋은 정의가 아닙니다. 부작용은 참조 투명성을 손상시키는 것으로 정의 될 수 있습니다. 여기에 표시하려고 시도한 것은 RT이지만 예제가 잘못되었습니다. 여러 번 실행하면 여러 번 같은 작업을 수행 val a = println("hello"); val b = (a, a)해야하므로 오히려 동일해야합니다 val b = (pritnln("hello"), println("hello")).
Luis Miguel Mejía Suárez

1
@ LuisMiguelMejíaSuárez 아마도 내 예가 명확하지 않지만 잘못되었다고 생각하지 않습니다. 본질적으로 프로그램 println(5)과 의 차이점을 지적 하고 ()있습니다. 아니면 마지막 문장을 의미 했습니까?
joelb

예, 그러나 당신은 그것에 대해 명확하지 않았습니다. 내가 말했듯이 문제는 여러 번 호출하지 않으므로 참조를 정의로 바꾸면 그 영향이 발생합니다.
Luis Miguel Mejía Suárez

나는 명확 예를 이해하지 못하는
aName

5
나는 부작용이 있고 dem 등성이 있기 때문에 반복해도 효과가 변하지 않기 때문에 그것이 잘못되었다고 말하고 싶습니다. 예를 들어 가변 변수에 할당; 당신은 어떻게 구별 할 수 x = 1x = 1; x = 1; x = 1?
Alexey Romanov

5

다음 비유를 고려하십시오

var out: String = ""
def myprintln(s: String) = {
  out += s // this non-local mutation makes me impure
  ()
}

여기 myprintln불순한이므로 값을 반환 옆 ()그것은 또한 변이 비 로컬 변수 out부작용있다. 이제 out스트림 바닐라 println돌연변이가 있다고 상상해보십시오 .


1
응답 해 주셔서 감사합니다. 함수가
불완전한

1
@aName 값 ()을 반환 할 뿐 아니라의 로컬이 아닌 상태도 변경 System.out합니다.
마리오 갈릭

이 대답에서 빠진 중요한 사실은 println이 줄 바꿈 문자를 입력에 추가한다는 것입니다.
Federico S

4

부작용은 컴퓨터 상태입니다. println()주어진 값을 터미널에 표시하기 위해 메모리 상태가 변경 될 때마다 변경됩니다. 또는보다 일반적으로 표준 출력 스트림의 상태가 변경됩니다.


1
부분적으로 사실, 모든 작업을 수행하면 명령 카운터의 상태가되므로 부작용이 있습니다. 부작용의 정의는 참조 투명성의 정의에서 파생되며, 많은 사람들이 공유 변경 가능 상태에 대한 수정 측면에서 정의합니다.
Luis Miguel Mejía Suárez

2
이런 식으로, 어떤 기능, 작동 ....은 메모리 cpu .....,의 상태가 바뀌기 때문에
불완전합니다

2

이 질문에 대한 좋은 답변이 이미 제공되었지만 2 센트를 추가하겠습니다.

당신이 안에 보면됩니다 println기능 본질적으로는 동일합니다 java.lang.System.out.println()- 그래서 때를 스칼라의 표준 라이브러리 호출 println이 방법을 호출 후드 아래 방법 printlnPrintStream필드로 선언 된 객체 인스턴스 out에서 System(보다 정확하게 또는 클래스 outVar에서 Console그 내부 상태를 변경 개체), . 이것은 왜 println불순한 기능 인지 에 대한 또 다른 설명으로 간주 될 수 있습니다 .

도움이 되었기를 바랍니다!


1

그것은 참조 투명성 의 개념과 관련이 있습니다. 프로그램을 변경하지 않고 평가 결과로 대체 할 수 있으면 표현식은 참조 용으로 투명합니다 .

표현식이 참조 적으로 투명하지 않으면 부작용 이 있다고 말합니다 .

f(println("effect"), println("effect"))
// isn't really equivalent to!
val x = println("effect")
f(x, x)

동안

import cats.effect.IO

def printlnIO(line: String): IO[Unit] = IO(println(line))

f(printlnIO("effect"), printlnIO("effect"))
// is equivalent to
val x = printlnIO("effect")
f(x, x)

https://typelevel.org/blog/2017/05/02/io-monad-for-cats.html에서 자세한 설명을 찾을 수 있습니다.


f (x, x)가 f (println ( "effect"), println ( "effect"))와 다른 이유를 모르겠습니다.
a 이름

f(println("effect"), println("effect"))콘솔 "효과"에서 두 번 인쇄하는 동안 val x = println("effect");f(x,x)한 번 인쇄합니다.
Didac 몬테로

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