State, ST, IORef 및 MVar의 차이점
48 시간 내에 Write Yourself a Scheme (최대 85 시간)을 통해 작업 중이며 Add Variables and Assignments에 대한 부분에 도달했습니다 . 이 장에는 큰 개념적 도약이 있으며, 최종 솔루션으로 바로 이동하는 것보다 중간에 좋은 리팩토링을 통해 두 단계로 완료 되었으면합니다. 어쨌든…
나는 같은 목적을 제공하는 것 다른 클래스의 번호와 분실 들어 왔 : State
, ST
, IORef
,와 MVar
. 처음 세 개는 텍스트에 언급되어 있지만 마지막 세 개는 처음 세 개에 대한 많은 StackOverflow 질문에 대한 선호하는 답변 인 것 같습니다. 그들은 모두 연속 호출 사이에 상태를 가지고있는 것 같습니다.
이들 각각은 무엇이며 서로 어떻게 다릅니 까?
특히 다음 문장은 의미가 없습니다.
대신 우리는 상태 스레드 라는 기능을 사용 하여 Haskell이 집계 상태를 관리 할 수 있도록합니다. 이를 통해 변수를 가져 오거나 설정하는 함수를 사용하여 다른 프로그래밍 언어 에서처럼 변경 가능한 변수를 처리 할 수 있습니다.
과
IORef 모듈을 사용하면 IO 모나드 내에서 상태 저장 변수를 사용할 수 있습니다 .
이 모든 것이 라인을 type ENV = IORef [(String, IORef LispVal)]
혼란스럽게 만듭니다 IORef
. type ENV = State [(String, LispVal)]
대신 글을 쓰면 무엇이 깨질 까요?
State Monad : 변경 가능한 상태의 모델
State 모나드는 상태가있는 프로그램을위한 순전히 기능적인 환경이며 간단한 API를 사용합니다.
- 가져 오기
- 놓다
mtl 패키지의 문서 .
State 모나드는 일반적으로 단일 제어 스레드에서 상태가 필요할 때 사용됩니다. 실제로 구현에서 변경 가능한 상태를 사용하지 않습니다. 대신, 프로그램은 상태 값에 의해 매개 변수화됩니다 (즉, 상태는 모든 계산에 대한 추가 매개 변수 임). 상태는 단일 스레드에서만 변경된 것처럼 보입니다 (스레드간에 공유 될 수 없음).
ST 모나드와 STRef
ST 모나드는 IO 모나드의 제한된 사촌입니다.
머신에서 실제 변경 가능한 메모리로 구현되는 임의의 변경 가능한 상태를 허용 합니다. API는 부작용이없는 프로그램에서 안전합니다. rank-2 유형 매개 변수는 변경 가능한 상태에 의존하는 값이 로컬 범위를 벗어나는 것을 방지하기 때문입니다.
따라서 순수한 프로그램에서 제어 된 가변성을 허용합니다.
일반적으로 변경 가능한 배열 및 변경된 후 고정되는 기타 데이터 구조에 사용됩니다. 또한 변경 가능한 상태가 "하드웨어 가속"이기 때문에 매우 효율적입니다.
기본 API :
- Control.Monad.ST
- runST-새로운 메모리 효과 계산을 시작합니다.
- 그리고 STRefs : (로컬) 변경 가능한 셀에 대한 포인터.
- ST 기반 배열 (예 : 벡터)도 일반적입니다.
IO 모나드의 덜 위험한 형제라고 생각하십시오. 또는 메모리에 읽기 및 쓰기 만 가능한 IO.
IORef : IO의 STRef
이들은 IO 모나드의 STRef (위 참조)입니다. 지역에 대한 STRef와 동일한 안전 보장이 없습니다.
MVars : 잠금이있는 IORef
STRef 또는 IORef와 비슷하지만 여러 스레드에서 안전하게 동시 액세스 할 수 있도록 잠금이 연결되어 있습니다. IORef 및 STRef는 atomicModifyIORef
(비교 및 교체 원자 연산)을 사용할 때 다중 스레드 설정에서만 안전 합니다. MVar는 변경 가능한 상태를 안전하게 공유하기위한보다 일반적인 메커니즘입니다.
일반적으로 Haskell에서는 STRef 또는 IORef를 통해 MVars 또는 TVars (STM 기반 가변 셀)를 사용합니다.
좋습니다 IORef
. 시작하겠습니다 . IORef
IO 모나드에서 변경 가능한 값을 제공합니다. 일부 데이터에 대한 참조 일 뿐이며 다른 참조와 마찬가지로 참조하는 데이터를 변경할 수있는 함수가 있습니다. Haskell에서 이러한 모든 함수는 IO
. 데이터베이스, 파일 또는 기타 외부 데이터 저장소처럼 생각할 수 있습니다. 데이터를 가져오고 설정할 수 있지만 그렇게하려면 IO를 거쳐야합니다. IO가 필요한 이유는 Haskell이 순수 하기 때문입니다 . 컴파일러는 주어진 시간에 참조가 어떤 데이터를 가리키는 지 알 수있는 방법이 필요합니다 ( sigfpe의 "You could have invented monads" 블로그 게시물 참조).
MVar
두 가지 매우 중요한 차이점을 제외하고는 기본적으로 IORef와 동일합니다. MVar
동시성 프리미티브이므로 여러 스레드에서 액세스하도록 설계되었습니다. 두 번째 차이점은 an MVar
이 가득 차거나 비어있을 수있는 상자라는 것입니다. 따라서 a가 IORef Int
항상있는 경우 Int
(또는 맨 아래), an MVar Int
이 Int
있거나 비어있을 수 있습니다. 스레드가 비어있는 값을 읽으려고하면 다른 스레드가 채워질 MVar
때까지 차단됩니다 MVar
. 기본적으로 an MVar a
은 IORef (Maybe a)
동시성에 유용한 추가 의미 체계 가있는 것과 동일 합니다.
State
is a monad which provides mutable state, not necessarily with IO. In fact, it's particularly useful for pure computations. If you have an algorithm that uses state but not IO
, a State
monad is often an elegant solution.
There is also a monad transformer version of State, StateT
. This frequently gets used to hold program configuration data, or "game-world-state" types of state in applications.
ST
is something slightly different. The main data structure in ST
is the STRef
, which is like an IORef
but with a different monad. The ST
monad uses type system trickery (the "state threads" the docs mention) to ensure that mutable data can't escape the monad; that is, when you run an ST computation you get a pure result. The reason ST is interesting is that it's a primitive monad like IO, allowing computations to perform low-level manipulations on bytearrays and pointers. This means that ST
can provide a pure interface while using low-level operations on mutable data, meaning it's very fast. From the perspective of the program, it's as if the ST
computation runs in a separate thread with thread-local storage.
Others have done the core things, but to answer the direct question:
All this makes the line type
ENV = IORef [(String, IORef LispVal)]
confusing. Why the second IORef? What will break if I dotype ENV = State [(String, LispVal)]
instead?
Lisp is a functional language with mutable state and lexical scope. Imagine you've closed over a mutable variable. Now you've got a reference to this variable hanging around inside some other function -- say (in haskell-style pseudocode) (printIt, setIt) = let x = 5 in (\ () -> print x, \y -> set x y)
. You now have two functions -- one prints x, and one sets its value. When you evaluate printIt
, you want to lookup the name of x in the initial environment in which printIt
was defined, but you want to lookup the value that name is bound to in the environment in which printIt
is called (after setIt
may have been called any number of times).
There are ways besids the two IORefs to do this, but you certainly need more than the latter type you've proposed, which doesn't allow you to alter the values that names are bound to in a lexically-scoped fashion. Google the "funargs problem" for a whole lot of interesting prehistory.
참고URL : https://stackoverflow.com/questions/5545517/difference-between-state-st-ioref-and-mvar
'Programing' 카테고리의 다른 글
JavaScript로 GetElementById 대신 getElementByClass를 사용하는 방법은 무엇입니까? (0) | 2020.09.12 |
---|---|
Graph API를 사용하는 Facebook 'Friends.getAppUsers' (0) | 2020.09.12 |
ARC를 사용하고 iOS 4.0을 대상으로 할 때 약한 참조를 어떻게 대체합니까? (0) | 2020.09.12 |
node.js에서 쉘 명령의 출력을 실행하고 가져옵니다. (0) | 2020.09.12 |
Microsoft.DotNet.Props를 찾을 수 없습니다. (0) | 2020.09.12 |