기능 언어는 정의상 상태 변수를 유지해서는 안됩니다. 그렇다면 Haskell, Clojure 등이 소프트웨어 트랜잭션 메모리 (STM) 구현을 제공하는 이유는 무엇입니까? 두 접근 방식간에 충돌이 있습니까?
기능 언어는 정의상 상태 변수를 유지해서는 안됩니다. 그렇다면 Haskell, Clojure 등이 소프트웨어 트랜잭션 메모리 (STM) 구현을 제공하는 이유는 무엇입니까? 두 접근 방식간에 충돌이 있습니까?
답변:
변경 가능한 상태를 유지하는 기능적 언어에는 아무런 문제가 없습니다. Haskell과 같은 "순수한"기능 언어조차도 실제 세계와 상호 작용하려면 상태를 유지해야합니다. Clojure와 같은 "Impure"기능 언어는 돌연변이 상태를 포함 할 수있는 부작용을 허용합니다.
요점은 기능적 언어가 실제로 필요한 경우가 아니라면 가변 상태를 권장하지 않는다는 것 입니다. 일반적인 스타일은 순수한 함수와 불변 데이터를 사용하여 프로그래밍하고, 코드의 특정 부분에서 "불완전한"가변 상태와 만 상호 작용하는 것입니다. 이렇게하면 나머지 코드베이스를 "순수"하게 유지할 수 있습니다.
기능 언어에서 STM이 더 일반적인 이유는 여러 가지가 있다고 생각합니다.
저는 개인적으로 Clojure가 변경을 허용하는 방식을 좋아하지만 STM 트랜잭션에 참여할 수있는 엄격하게 통제 된 "관리되는 참조"의 맥락에서만 가능합니다. 언어의 다른 모든 것은 "순전히 기능적"입니다.
;; define two accounts as managed references
(def account-a (ref 100))
(def account-b (ref 100))
;; define a transactional "transfer" function
(defn transfer [ref-1 ref-2 amount]
(dosync
(if (>= @ref-1 amount)
(do
(alter ref-1 - amount)
(alter ref-2 + amount))
(throw (Error. "Insufficient balance!")))))
;; make a stranfer
(transfer account-a account-b 75)
;; inspect the accounts
@account-a
=> 25
@account-b
=> 175
위의 코드는 완전히 거래 적이며 원자 적입니다. 다른 트랜잭션 내에서 두 개의 잔액을 읽는 외부 관찰자는 항상 일관된 원자 상태를 보게됩니다. 즉, 두 개의 잔액은 항상 200으로 합산됩니다. 잠금 기반 동시성에서는 놀랍게도 어려운 문제입니다 많은 거래 엔터티가있는 대규모 복잡한 시스템에서 해결합니다.
더 많은 깨달음을 위해 Rich Hickey는 이 비디오에서 Clojure의 STM을 설명 하는 훌륭한 일을합니다.
때로는 프로그램에 가변 상태 (예 : 웹앱의 데이터베이스 내용)가 필요하며 기능적 프로그래밍 의 이점 을 잃지 않고 사용할 수있는 것이 좋습니다 . 작동하지 않는 언어에서 가변 상태는 모든 것에 스며 듭니다. 특정 종류의 특수 API로 명시 적으로 지정 하면 식별 가능한 작은 영역으로 제한 할 수 있지만 다른 모든 기능은 순수하게 작동합니다. FP의 이점은보다 쉬운 디버깅, 반복 가능한 단위 테스트, 무통 동시성 및 멀티 코어 / GPU 친 화성입니다.