함수라고하는 참조 투명도는 인수 값을보고 만 해당 함수를 적용한 결과를 결정할 수 있음을 나타냅니다. Python, Scheme, Pascal, C와 같은 프로그래밍 언어로 참조 용으로 투명한 함수를 작성할 수 있습니다.
반면에 대부분의 언어에서는 참조가 아닌 투명한 함수를 작성할 수도 있습니다. 예를 들어,이 Python 함수는
counter = 0
def foo(x):
global counter
counter += 1
return x + counter
실제로 전화하는 것은 투명하지 않습니다.
foo(x) + foo(x)
과
2 * foo(x)
인수에 대해 다른 값을 생성합니다 x
. 그 이유는 함수가 전역 변수를 사용하고 수정하기 때문에 각 호출의 결과는 함수의 인수뿐만 아니라이 변경 상태에 따라 달라지기 때문입니다.
하스켈, 순수 함수형 언어가 엄격히 분리 식 평가 하는 순수한 기능 인가로부터 항상 referentially 투명되는 동작 실행 마다 A를 가질 수있는 동일한 기능을 실행 referentially 투명하지 않다 (특별 값들의 처리), 즉 다른 결과.
어떤 하스켈 함수 든
f :: Int -> Int
그리고 모든 정수 x
는 항상
2 * (f x) == (f x) + (f x)
조치의 예는 라이브러리 함수의 결과입니다 getLine
.
getLine :: IO String
식 평가의 결과로이 함수 (실제로 상수)는 우선 순수한 type 값을 생성합니다 IO String
. 이 유형의 값은 다른 값과 같습니다. 값을 전달하고, 데이터 구조에 넣고, 특수 함수를 사용하여 작성하는 등의 작업을 수행 할 수 있습니다. 예를 들어 다음과 같은 작업 목록을 만들 수 있습니다.
[getLine, getLine] :: [IO String]
작업은 다음과 같이 작성하여 Haskell 런타임에 실행하도록 지시 할 수 있다는 점에서 특별합니다.
main = <some action>
이 경우, 하스켈 프로그램이 시작될 때, 런타임에 바인딩 작업을 통해 안내 main
하고 실행 가능한 부작용을 생산하고, 그것을. 따라서 동일한 조치를 두 번 실행하면 런타임이 입력으로 가져 오는 내용에 따라 다른 결과가 생성 될 수 있으므로 조치 실행은 참조 적으로 투명하지 않습니다.
Haskell의 유형 시스템 덕분에 다른 유형이 예상되는 상황에서는 작업을 사용할 수 없으며 그 반대도 마찬가지입니다. 따라서 문자열의 길이를 찾으려면 length
함수를 사용할 수 있습니다 .
length "Hello"
터미널에서 읽은 문자열의 길이를 찾으려면 쓸 수 없습니다.
length (getLine)
유형 오류가 발생하기 때문에 : length
유형 목록의 입력 (및 문자열은 실제로 목록)을 예상하지만 getLine
유형의 값 IO String
(조치)입니다. 이런 식으로, 타입 시스템은 getLine
(핵심 언어 외부에서 실행되고 비참 조적으로 투명 할 수있는) 같은 액션 값이 타입의 액션이 아닌 값 안에 숨겨 질 수 없도록합니다 Int
.
편집하다
exizt 질문에 대답하기 위해 콘솔에서 줄을 읽고 길이를 인쇄하는 작은 Haskell 프로그램이 있습니다.
main :: IO () -- The main program is an action of type IO ()
main = do
line <- getLine
putStrLn (show (length line))
기본 조치는 순차적으로 실행되는 두 개의 하위 조치로 구성됩니다.
getline
유형 IO String
의
- 두 번째는 인수에 대한
putStrLn
유형 의 함수 를 평가하여 구성됩니다 String -> IO ()
.
보다 정확하게는 두 번째 동작은
line
첫 번째 작업에서 읽은 값에 바인딩
- 순수 함수를
length
계산하고 (길이를 정수로 계산) show
정수를 문자열로 변환
- 함수를 적용함으로써 작업 구축
putStrLn
의 결과 show
.
이 시점에서 두 번째 작업을 실행할 수 있습니다. "Hello"를 입력 한 경우 "5"가 인쇄됩니다.
<-
표기법을 사용하여 조치에서 값을 얻는 경우 다른 조치 내에서만 해당 값을 사용할 수 있습니다 (예 : 쓸 수 없음).
main = do
line <- getLine
show (length line) -- Error:
-- Expected type: IO ()
-- Actual type: String
show (length line)
유형이 있기 때문에 String
do 표기법은 조치 ( getLine
유형 IO String
) 뒤에 다른 조치 (예 : putStrLn (show (length line))
유형 IO ()
)가 필요합니다.
편집 2
Jörg W Mittag의 참조 투명성에 대한 정의는 내 것보다 더 일반적입니다 (저는 그의 대답을 상향 조정했습니다). 질문의 예가 함수의 반환 값에 중점을 두고이 측면을 설명하고 싶기 때문에 제한된 정의를 사용했습니다. 그러나 일반적으로 RT는 전역 상태 변경 및 식 평가로 인한 환경 (IO)과의 상호 작용을 포함하여 전체 프로그램의 의미를 나타냅니다. 따라서 올바른 일반 정의를 위해서는 해당 답변을 참조해야합니다.