상태 저장 라이브러리 위에 부작용이없는 인터페이스


16

에서 존 휴즈와의 인터뷰 그가 얼랑 및 하스켈에 대해 이야기 그는 얼랑의 상태 라이브러리를 사용하는 방법에 대해 말할 다음이있다 :

상태 저장 라이브러리를 사용하려면 일반적으로 부작용이없는 인터페이스를 빌드하여 나머지 코드에서 안전하게 사용할 수 있습니다.

그는 이것이 무엇을 의미합니까? 나는 이것이 어떻게 보일지에 대한 예를 생각하려고 노력하고 있지만 나의 상상력과 지식이 나에게 실패하고 있습니다.


글쎄, 주가 존재한다면 사라지지 않을 것입니다. 비결은 의존성을 추적 할 무언가를 만드는 것입니다. 표준 Haskell의 대답은 "monads" 또는 고급 "arrows" 입니다. 그들은 당신의 머리를 감싸기가 약간 어렵고 나는 실제로 한 적이 없으므로 다른 누군가가 그것들을 설명하려고 시도해야합니다.
Jan Hudec

답변:


12

(나는 Erlang을 모르고 Haskell을 쓸 수 없지만 그럼에도 불구하고 대답 할 수 있다고 생각합니다)

이 인터뷰에서 난수 생성 라이브러리의 예가 제공됩니다. 가능한 상태 저장 인터페이스는 다음과 같습니다.

# create a new RNG
var rng = RNG(seed)

# every time we call the next(ceil) method, we get a new random number
print rng.next(10)
print rng.next(10)
print rng.next(10)

출력이 될 수 있습니다 5 2 7. 불변성을 좋아하는 사람에게는 이것이 잘못입니다! 5 5 5동일한 객체에서 메소드를 호출했기 때문에 이어야 합니다.

그렇다면 상태 비 저장 인터페이스는 무엇입니까? 난수 시퀀스를 지연 평가 된 목록으로 볼 수 있습니다. 여기서 next실제로 헤드를 검색합니다.

let rng = RNG(seed)
let n : rng = rng in
  print n
  let n : rng = rng in
    print n
    let n : rng in
      print n

이러한 인터페이스를 사용하면 언제든지 이전 상태로 되돌릴 수 있습니다. 코드의 두 조각이 동일한 RNG를 참조하면 실제로 동일한 숫자 시퀀스를 얻습니다. 기능적인 사고 방식에서 이것은 매우 바람직합니다.

상태 저장 언어로 이것을 구현하는 것은 그렇게 복잡하지 않습니다. 예를 들면 다음과 같습니다.

import scala.util.Random
import scala.collection.immutable.LinearSeq

class StatelessRNG (private val statefulRNG: Random, bound: Int) extends LinearSeq[Int] {
  private lazy val next = (statefulRNG.nextInt(bound), new StatelessRNG(statefulRNG, bound))

  // the rest is just there to satisfy the LinearSeq trait
  override def head = next._1
  override def tail = next._2
  override def isEmpty = false
  override def apply(i: Int): Int = throw new UnsupportedOperationException()
  override def length = throw new UnsupportedOperationException()
}

// print out three nums
val rng = new StatelessRNG(new Random(), 10)
rng.take(3) foreach (n => println(n))

일단 목록처럼 느껴지도록 약간의 구문 설탕을 추가하면 실제로는 아주 좋습니다.


1
첫 번째 예 : 매번 다른 값을 생성하는 rnd.next (10)은 함수 정의와 관련하여 불변성과 관련이 없습니다. 함수는 일대일이어야합니다. (+1, 좋은 것들)
Steven Evers

감사! 그것은 정말 좋고 설득력있는 설명과 예였습니다.
베타

1

여기서 핵심 개념은 외부 변경 가능 상태 의 개념 입니다. 외부 변경 가능 상태가없는 라이브러리는 부작용이없는 라이브러리입니다. 이러한 라이브러리의 모든 함수는 전달 된 인수에만 의존합니다.

  • 함수가 작성하지 않은 (예 : 매개 변수로) 자원에 액세스하는 경우 외부 상태에 따라 다릅니다 .
  • 함수가 호출자에게 전달되지 않고 파괴하지 않는 것을 생성하면 함수는 외부 상태를 생성합니다.
  • 위에서 외부 상태가 다른 시간에 다른 값을 가질 수 있으면 변경 가능 합니다.

내가 사용하는 편리한 리트머스 테스트 :

  • 기능 A가 기능 B보다 먼저 실행되어야하는 경우 A는 B가 의존하는 외부 상태를 작성합니다.
  • 쓰고있는 함수를 메모 할 수 없으면 외부 변경 가능 상태에 따라 달라집니다. (메모리 부족으로 인해 메모 화는 좋은 생각이 아니지만 여전히 가능해야합니다.)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.