문제

하나의 인수를 내가 들어에 대해 기능적인 언어는 하나의 할당 코딩이 너무 어렵거나,적어도 크게 보다 더 열심히"일반적인"프로그래밍입니다.

지만 코드,내가 깨달았는 내가 정말 많이 없(어떤?) 하는 패턴을 사용할 수 없이 쓰여 사용뿐만 아니라 하나의 할당 양식을 작성하는 경우에는 합리적으로 현대적인 언어입니다.

그래서 무엇을 사용하는 경우는 변수에 따라 다를 하나의 호출의 그들의 범위는?베어링 하는 마음에 루프 인덱스,매개변수,그리고 다른 범위밖에 없는 값이 달라질 호출이 없는 여러 과제 이 경우에는(당신이하지 않는 변화에서 그들을 위해 몸부),고 있다는 가정에서 쓰는 뭔가 충분히 위의 어셈블리 언어 수준에,어디를 작성할 수 있습 같은 것들

values.sum

나(경우에는 합이 제공되지 않)

function collection.sum --> inject(zero, function (v,t) --> t+v )

x = if a > b then a else b

n = case s 
  /^\d*$/ : s.to_int
  ''      : 0
  '*'     : a.length
  '?'     : a.length.random
  else    fail "I don't know how many you want"

할 때 필요하고,목록을 함축하도/를 수집,그리고 앞으로 사용할 수 있다.

당신은 당신을 찾는 여전히/할 필요한 변경 가능한 변수는 이와 같은 환경에서,그리고 만약 그렇다면,어떤가?

을 명확히,나는지에 대한 요구의 암송을 반대하 SSA 형태지만,오히려 구체적인 예는 그 반대 적용할 것입니다.내가 찾는 비트 코드는 명확하고 간결한을 가진 변수 및 수 없도록 작성합니다.

내가 좋아하는 예로는 지금까지(그리고 최고의 반대가 기대하여 그들):

  1. 바울은 존슨 Fisher-Yates 알고리즘 대답은 매우 강력한 경우를 포함합 big-O 제약 조건이 있습니다.하지만,catulahoops 점,big-O 문제에 묶이지 않 SSA 질문이 있지만,오히려하는 변경 데이터 형식과 함께하는 따로 설정 알고리즘을 작성할 수 있습라에서 명확하게 SSA:

     shuffle(Lst) ->
         array:to_list(shuffle(array:from_list(Lst), erlang:length(Lst) - 1)).
     shuffle(Array, 0) -> Array;
     shuffle(Array, N) ->
         K = random:uniform(N) - 1,
         Ek = array:get(K, Array),
         En = array:get(N, Array),
         shuffle(array:set(K, En, array:set(N, Ek, Array)), N-1).
    
  2. jpalecek 의 지역의 다각형 예제:

    def area(figure : List[Point]) : Float = {
      if(figure.empty) return 0
      val last = figure(0)
      var first= figure(0)
      val ret = 0
      for (pt <- figure) {
        ret+=crossprod(last - first, pt - first)
        last = pt
      }
      ret
    }
    

    수도 있는 여전히 쓰여 다음과 같습니다.

    def area(figure : List[Point]) : Float = {
        if figure.length < 3
            0
          else
            var a = figure(0)
            var b = figure(1)
            var c = figure(2)
            if figure.length == 3
                magnitude(crossproduct(b-a,c-a))
              else 
                foldLeft((0,a,b))(figure.rest)) { 
                   ((t,a,b),c) => (t+area([a,b,c]),a,c)
                   }
    

    또는,사람들 때문에 객체의 밀도 이제,그것은 수 만들다:

    def area([])    = 0.0   # An empty figure has no area
    def area([_])   = 0.0   # ...nor does a point
    def area([_,_]) = 0.0   # ...or a line segment
    def area([a,b,c]) =     # The area of a triangle can be found directly
        magnitude(crossproduct(b-a,c-a))
    def area(figure) =      # For larger figures, reduce to triangles and sum
        as_triangles(figure).collect(area).sum
    
    def as_triangles([])      = []  # No triangles without at least three points
    def as_triangles([_])     = []
    def as_triangles([_,_])   = []
    def as_triangles([a,b,c | rest) = [[a,b,c] | as_triangles([a,c | rest])]
    
  3. 공주의점 어려움에 대해의 구현 O(1)큐를 변경할 수 없는 구조물이 재미있(수 있습니다 기초를 제공한 강제적인 예)하지만 명시된 바와 같이 그것의 근본적으로의 가변성은 데이터 구조,그리고 직접적에 대해 여러 배정 문제입니다.

  4. 나는 흥미로는 에라토스테네스의 체 응답하지만,모호하다.적절한 big-O,풀로 많은 소수 업데이기에 주어지는 인용하지 않는 모습에 쉽게 구현하는 올바르게 함께 또는없이 SSA.


론,주셔서 감사합니다 모두가 하려고합니다.대부분의 답변을 밝혀졌다 중 1)에 따라 변경 가능한 데이터 구조,지에서 한 할당,그리고 2)어느 정도 그들에 대해 하나의 할당 형태로 쉽게 무효화된 실무자들에 의해 숙련된 기술에서,나는 공격하는 선에서 이야기 나 그리고/또는 재구성(어쩌면 그것에 백업으로 토론 주제에 나는 단어에서 실행하기 전에 나는 실행 시간).

다시 한번 감사드립니다.

도움이 되었습니까?

해결책

나는 그런 경우를 식별 한 적이 없다. SSA 형식으로 변환하는 것처럼 항상 새로운 이름을 발명 할 수 있지만 실제로 각 값이 자체 이름을 갖기 쉽고 자연 스럽습니다. Haskell과 같은 언어는 이름을 지정할 값에 대해 많은 선택과 이름 바인딩을 넣을 두 개의 다른 장소를 제공합니다 (let 그리고 where). 나는 단일 할당 형태가 상당히 자연스럽고 전혀 어렵지 않다는 것을 알았습니다.

나는 때때로 힙에 변한 물체에 대한 포인터를 가질 수 있다는 것을 놓친다. 그러나 이러한 것들은 이름이 없으므로 같은 반대 의견이 아닙니다. (그리고 나는 또한 힙에 변한 물체를 사용할 때 더 많은 버그를 쓰는 경향이 있음을 알았습니다!)

다른 팁

가장 어려운 문제가입니다 섞습니다.이 Fisher-Yates 알고리즘(또한 때때로 알려져 있으로 Knuth 알고리즘)포함을 반복하고 목록을 교환하여 각 항목을 임의의 다른 항목입니다.알고리즘 O(n),잘 알려져 있고 장기 때문 입증된 올바른(중요한 시설에는 일부 응용 프로그램).하지만 그것은 필요한 변경을 배열할 수 있습니다.

지 않는 말을 할 수 없는 셔플에 기능적인 프로그램입니다.올 Kiselyov 가 기록에 대해 이.하지만 만약 내가 그를 이해하고 올바르게 기능을 섞 O(n.로그 n)작동하기 때문에 구축하여 바이너리 나무입니다.

물론,필요한 경우 내가 쓰는 피셔-Yates 알고리즘에서도 사용할 나이에 넣어 ST 일, 할 수 있는 포장하는 알고리즘을 포함하는 가변 배열 안 좋은 순수한 기능은 다음과 같습니다.

-- | Implementation of the random swap algorithm for shuffling.  Reads a list
-- into a mutable ST array, shuffles it in place, and reads out the result
-- as a list.

module Data.Shuffle (shuffle) where


import Control.Monad
import Control.Monad.ST
import Data.Array.ST
import Data.STRef
import System.Random

-- | Shuffle a value based on a random seed.
shuffle :: (RandomGen g) => g -> [a] -> [a]
shuffle _ [] = []
shuffle g xs = 
    runST $ do
      sg <- newSTRef g
      let n = length xs
      v <- newListArray (1, n) xs
      mapM_ (shuffle1 sg v) [1..n]
      getElems v

-- Internal function to swap element i with a random element at or above it.
shuffle1 :: (RandomGen g) => STRef s g -> STArray s Int a -> Int -> ST s ()
shuffle1 sg v i = do
  (_, n) <- getBounds v
  r <- getRnd sg $ randomR (i, n)
  when (r /= i) $ do
    vi <- readArray v i
    vr <- readArray v r
    writeArray v i vr
    writeArray v r vi


-- Internal function for using random numbers
getRnd :: (RandomGen g) => STRef s g -> (g -> (a, g)) -> ST s a
getRnd sg f = do
  g1 <- readSTRef sg
  let (v, g2) = f g1
  writeSTRef sg g2
  return 

v

학업 논증을 원한다면 물론 변수를 두 번 이상 할당 할 필요는 없습니다. 증거는 모든 코드를 표시 할 수 있다는 것입니다. SSA (단일 정적 할당) 형태. 실제로, 그것은 많은 종류의 정적 및 동적 분석에 가장 유용한 형태입니다.

동시에, 우리가 모두 SSA 형식으로 코드를 작성하지 않는 이유가 있습니다.

  1. 이 방법으로 코드를 작성하려면 일반적으로 더 많은 진술 (또는 더 많은 코드 줄)이 필요합니다. 간결성은 가치가 있습니다.
  2. 거의 항상 덜 효율적입니다. 그렇습니다. 나는 당신이 고등어 (공정한 범위)에 대해 이야기하고 있다는 것을 알고 있습니다. 그러나 조립에서 멀리 떨어진 Java와 C#의 세계에서도 속도가 중요합니다. 속도가 관련이없는 응용 프로그램은 거의 없습니다.
  3. 이해하기 쉽지 않습니다. SSA는 수학적 의미에서 "단순한"것이지만, 상식에서 더 추상적이며, 이것이 실제 프로그래밍에서 중요한 것입니다. 당신이 그것을 맥주하기 위해 정말로 똑똑해야한다면, 그것은 프로그래밍에 큰 자리가 없습니다.

위의 예에서도 구멍을 뚫기 쉽습니다. 당신의 case 성명. 관리 옵션이 있는지 확인하는 관리 옵션이있는 경우 '*' 허용되고, 별도의 것 '?' 허용됩니까? 또한 사용자가이를 허용하는 시스템 권한이없는 한 정수 케이스에는 0이 허용되지 않습니다.

이것은 분기와 조건이있는보다 실제적인 예입니다. 이것을 하나의 "진술"으로 쓸 수 있습니까? 그렇다면 "진술"이 많은 별도의 진술과는 정말 다릅니 까? 그렇지 않은 경우, 몇 개의 임시 쓰기 전용 변수가 필요합니까? 그리고 그 상황이 단일 변수를 갖는 것보다 훨씬 낫습니까?

가장 생산적인 언어를 찾으면 OCAML 및 F#과 같은 기능적이고 명령적인 스타일을 혼합 할 수 있습니다.

대부분의 경우 "맵 x에서 y까지, y를 z로 줄인다"라는 코드를 쓸 수 있습니다. 95%의 경우 기능 프로그래밍은 내 코드를 단순화하지만 불변성이 치아를 보여주는 영역이 하나 있습니다.

구현 용이성과 불변의 스택과 불변의 대기열 사이의 광범위한 불일치.

스택은 쉽고 끈기와 잘 맞으며 대기열은 말도 안됩니다.

제일 불변의 대기열의 일반적인 구현 하나 이상의 내부 스택과 스택 회전을 사용하십시오. 거꾸로 된 것은이 대기열이 O (1)에서 실행된다는 것입니다. 대부분의 시간, 그러나 일부 작업은 O (N)에서 실행됩니다. 응용 프로그램에서 지속성에 의존하는 경우 원칙적으로 모든 작업이 O (N)로 실행될 가능성이 있습니다. 이 대기열은 실시간 (또는 적어도 일관된) 성능이 필요할 때 좋지 않습니다.

Chris Okasaki 's는 불변의 대기열을 구현합니다. 그의 책, 그들은 모든 작업에 대해 O (1)을 달성하기 위해 게으름을 사용합니다. 실시간 대기열의 매우 영리하고 합리적으로 간결한 구현이지만 기본 구현 세부 사항에 대한 깊은 이해가 필요하며 여전히 불변의 스택보다 더 복잡한 순서입니다.

Constrast에서는 모든 작업에 대해 일정한 시간 내에 실행되는 Mutable Linked Lists를 사용하여 스택과 큐를 작성할 수 있으며 결과 코드는 매우 간단합니다.


다각형의 영역과 관련하여 기능적 형태로 쉽게 변환 할 수 있습니다. 다음과 같은 벡터 모듈이 있다고 가정 해 봅시다.

module Vector =
    type point =
        { x : float; y : float}
        with
            static member ( + ) ((p1 : point), (p2 : point)) =
                { x = p1.x + p2.x;
                  y = p1.y + p2.y;}

            static member ( * ) ((p : point), (scalar : float)) =
                { x = p.x * scalar;
                  y = p.y * scalar;}

            static member ( - ) ((p1 : point), (p2 : point)) = 
                { x = p1.x - p2.x;
                  y = p1.y - p2.y;}

    let empty = { x = 0.; y = 0.;}
    let to_tuple2 (p : point) = (p.x, p.y)
    let from_tuple2 (x, y) = { x = x; y = y;}
    let crossproduct (p1 : point) (p2 : point) =
        { x = p1.x * p2.y; y = -p1.y * p2.x }

우리는 약간의 튜플 마법을 사용하여 지역 기능을 정의 할 수 있습니다.

let area (figure : point list) =
    figure
    |> Seq.map to_tuple2
    |> Seq.fold
        (fun (sum, (a, b)) (c, d) -> (sum + a*d - b*c, (c, d) ) )
        (0., to_tuple2 (List.hd figure))
    |> fun (sum, _) -> abs(sum) / 2.0

또는 대신 크로스 제품을 사용할 수 있습니다

let area2 (figure : point list) =
    figure
    |> Seq.fold
        (fun (acc, prev) cur -> (acc + (crossproduct prev cur), cur))
        (empty, List.hd figure)
    |> fun (acc, _) -> abs(acc.x + acc.y) / 2.0

기능을 읽을 수없는 기능을 찾을 수 없습니다.

이 셔플 알고리즘은 단일 할당을 사용하여 구현하기가 사소한 일입니다. 실제로 반복이 테일 재귀로 다시 작성된 명령 솔루션과 정확히 동일합니다. (Haskell보다 더 빨리 쓸 수 있기 때문에 Erlang.)

 shuffle(Lst) ->
     array:to_list(shuffle(array:from_list(Lst), erlang:length(Lst) - 1)).

 shuffle(Array, 0) -> Array;
 shuffle(Array, N) ->
     K = random:uniform(N) - 1,
     Ek = array:get(K, Array),
     En = array:get(N, Array),
     shuffle(array:set(K, En, array:set(N, Ek, Array)), N-1).

해당 배열 작업의 효율성이 문제라면, 이는 변이 가능한 데이터 구조에 대한 의문이며 단일 할당과 관련이 없습니다.

예제가 없기 때문에이 질문에 대한 답을 얻지 못합니다. 이 스타일에 대한 친숙한 문제 일뿐입니다.

Jason에 대한 응답으로 -

function forbidden_input?(s)
    (s = '?' and not administration.qmark_ok) ||
    (s = '*' and not administration.stat_ok)  ||
    (s = '0' and not 'root node visible' in system.permissions_for(current_user))

n = if forbidden_input?(s)
    fail "'" + s + "' is not allowed."
  else
    case s
      /^\d*$/ : s.to_int
      ''      : 0
      '*'     : a.length
      '?'     : a.length.random
      else    fail "I don't know how many you want"

나는 불완전하지 않은 언어로 과제를 놓칠 것입니다. 대부분은 루프의 유용성을 방해하기 때문입니다. 예제 (Scala) :

def quant[A](x : List[A], q : A) = {
  var tmp : A=0
  for (el <- x) { tmp+= el; if(tmp > q) return el; }
  // throw exception here, there is no prefix of the list with sum > q
}

이것은 목록의 Quantile을 계산해야합니다. tmp 여러 번 할당됩니다.

비슷한 예는 다음과 같습니다.

def area(figure : List[Point]) : Float = {
  if(figure.empty) return 0
  val last = figure(0)
  var first= figure(0)
  val ret = 0
  for (pt <- figure) {
    ret+=crossprod(last - first, pt - first)
    last = pt
  }
  ret
}

주로 참고하십시오 last 변하기 쉬운.

이 예제는 여러 할당을 피하기 위해 튜플에 폴드를 사용하여 다시 작성할 수 있지만 실제로 가독성에 도움이되지는 않습니다.

로컬 (방법) 변수는 확실히 결코 없습니다 가지다 두 번 할당됩니다. 그러나 기능 프로그래밍에서도 변수를 재 할당 할 수 있습니다. 이것의 바꾸다 허용되지 않는 값 (일부). 그리고 Dsimcha가 이미 대답했듯이, 매우 큰 구조 (아마도 응용 프로그램의 근본)에 대해 전체 구조를 대체하는 것은 실현 가능한 것처럼 보이지 않습니다. 그것에 대해 생각하십시오. 응용 프로그램의 상태는 모두 궁극적으로 응용 프로그램의 EntryPoint 메소드에 의해 포함됩니다. 교체하지 않고 전혀 변경할 수 없다면 모든 키 스트로크와 함께 응용 프로그램을 다시 시작해야합니다. :(

게으른 목록/트리를 구축하는 함수가있는 경우 다시 감소하면 기능 컴파일러가 사용하여 최적화 할 수 있습니다. 삼림 벌채.

까다 롭다면 그렇지 않을 수도 있습니다. 그런 다음 부패성 변수를 반복하고 사용할 수 없다면 운이 좋지 않습니다.

교회 타이어 논문 덕분에 우리는 튜링에 완료 된 언어로 쓸 수있는 모든 것이 어느 튜링-완성 언어. 따라서, 당신이 그것에 바로 얻을 때, 당신이 C#에서 할 수없는 LISP에서 할 수없는 일은 없습니다. (어쨌든 대부분의 경우 x86 머신 언어로 편집 될 것입니다.)

따라서 귀하의 질문에 대한 답변은 다음과 같습니다. 그러한 사례는 없습니다. 인간이 하나의 패러다임/언어 또는 다른 사람으로 이해하기 쉬운 사례가 있는데, 여기서 이해의 용이성은 훈련과 경험과 관련이 있습니다.

아마도 여기서 주요 문제는 언어로의 반복 스타일 일 것입니다. 우리가 재귀를 사용하는 랑가우스에서는 함수가 다시 호출 될 때 루프 과정에서 변경되는 값이 다시 바인딩됩니다. 블록에서 반복자를 사용하는 언어 (예 : Smalltalk 's 및 Ruby's inject 루비의 많은 사람들이 여전히 사용하지만 방법)은 비슷한 경향이 있습니다. each 그리고 돌연변이 변수 이상 inject.

사용하는 루프를 사용하는 경우 while 그리고 for, 반면에, 여러 매개 변수를 루프를 반복하는 코드 덩어리에 여러 매개 변수를 전달할 수있을 때 자동으로 오는 변수를 쉽게 다시 연결하지 않으므로 불변의 변수는 다소 불편할 것입니다.

Haskell에서 작업하는 것은 기본값이 불변이지만 변이 가능한 변수이기 때문에 변수 변수의 필요성을 조사하는 정말 좋은 방법입니다 ( IORefs, MVars, 등등). 나는 최근에 이런 식으로 "조사"를했다. 그리고 다음과 같은 결론에 도달했다.

  1. 대부분의 경우 변수 변수는 필요하지 않으며, 나는 그것들이 없으면 행복합니다.

  2. 스레드 간 통신의 경우 상당히 명백한 이유로 변수 변수가 필수적입니다. (이것은 Haskell에 따라 다릅니다. 가장 낮은 수준으로 전달되는 메시지를 사용하는 런타임 시스템은 물론 필요하지 않습니다.) 그러나이 사용은 기능을 사용하여 읽고 쓰는 것만 큼 드물다 (().readIORef fooRef val 등은 큰 부담이 아닙니다.

  3. 나는 단일 스레드 내에서 변수 변수를 사용했습니다. 왜냐하면 특정 사물을 더 쉽게 만들어주는 것처럼 보였지만 나중에 저장된 가치에 대해 추론하기가 매우 어려워 졌다는 것을 깨달았을 때 후회했습니다. (몇 가지 다른 기능이 그 가치를 조작하고있었습니다.) 이것은 약간의 눈을 뜨게했습니다. 전형적인 개구리 개구리-워트 워터 스타일에서, 나는 Haskell이 내가 사용하는 방법에 대한 예를들을 때까지 값의 사용에 대해 추론하기 위해 얼마나 쉬운 지 깨닫지 못했습니다. .

그래서 요즘 나는 불변의 변수 측면에서 상당히 단호하게 내려 왔습니다.

이 질문에 대한 이전의 답변은 이러한 것들을 혼란스럽게했기 때문에, 나는이 문제가 순도와 기능적 프로그래밍 모두에 직교하다는 것을 매우 강력하게 지적해야한다고 생각합니다. 예를 들어, 루비는 단일 할당 지역 변수를 보는 것이 혜택을받을 수 있지만, 이는 재귀를 추가하는 것과 같은 언어에 대한 몇 가지 다른 변경이 필요할 것입니다.

큰 데이터 구조를 작은 변경해야 할 때는 어떻습니까? 몇 가지 요소를 수정할 때마다 전체 배열 또는 대형 클래스를 복사하고 싶지 않습니다.

나는 당신이 그것을 지적한다는 것을 제외하고는 이것에 대해 정말로 생각하지 않았습니다.

실제로 나는 무의식적으로 여러 과제를 사용하지 않습니다.

파이썬에서 내가 말하는 내용의 예는 다음과 같습니다.

start = self.offset%n
if start:
    start = n-start

불필요한 추가 모듈로 또는 뺄셈을 피하기 위해이 방법으로 작성되었습니다. 이것은 Bignum Style Long Ints와 함께 사용되므로 가치있는 최적화입니다. 그러나 그것에 대한 것은 실제로 단일 과제라는 것입니다.

나는 여러 과제를 전혀 놓치지 않을 것입니다.

나는 당신이 변수 변수의 이점을 보여준 코드를 요청한 것을 알고 있습니다. 그리고 나는 그것을 제공 할 수 있기를 바랍니다. 그러나 이전에 지적했듯이 - 두 패션으로 표현할 수없는 문제는 없습니다. 특히 Jpalecek의 다각형 예제 영역이 접이식 알고 (IMHO Way Messier이며 다른 수준의 복잡성에 문제를 가져옵니다)로 쓸 수 있다고 지적한 이후로, 왜 당신이 왜 돌연변이를 내려 오는지 궁금해했습니다. 딱딱한. 그래서 나는 공통된 근거와 불변적이고 변한 데이터의 공존에 대한 논쟁을 시도 할 것입니다.

내 의견으로는이 질문은 요점을 조금 놓친다. 나는 미국 프로그래머가 깨끗하고 단순한 것을 좋아하는 경향이 있다는 것을 알고 있지만 때로는 혼합물도 가능하다는 것을 놓친다는 것을 알고 있습니다. 그렇기 때문에 불변성에 대한 토론에서 누군가가 중간에있는 사람이 거의없는 이유 일 것입니다. 왜 그런지 궁금합니다. 불변성은 훌륭한 도구입니다 모든 종류의 문제를 추상화하는 것. 그러나 때때로 그것은입니다 엉덩이에 큰 통증. 때로는 단순히 너무 제한적입니다. 그리고 그것만으로도 나를 멈추고 물건을 만들어줍니다. 우리는 정말로 돌연변이를 느슨하게하고 싶습니까? 정말로 하나입니까? 공통점이 없습니다 우리는 도착할 수 있습니까? 불변성은 언제 내 목표를 더 빨리 달성하는 데 도움이됩니까? 읽고 유지하기가 더 쉬운 솔루션은 무엇입니까? (나를 위해 가장 큰 질문입니다)

이러한 많은 질문들은 프로그래머의 취향과 그들이 프로그램에 사용되는 것에 의해 영향을받습니다. 따라서 일반적으로 대부분의 추진성 논증의 중심 인 병렬성 : 병렬성 :

종종 평행주의는 불변성을 둘러싼 논쟁에 던져집니다. 합리적인 시간 안에 100 개 이상의 CPU가 필요한 문제 세트를 작업했습니다. 그리고 그것은 나에게 매우 중요한 한 가지를 가르쳐주었습니다. 대부분의 경우 데이터의 그래프 조작을 병렬화하는 것은 실제로 병렬화하는 가장 효율적인 방법이 아닙니다. 확실히 혜택을 볼 수 있지만 불균형은 그 문제 공간에서 실제 문제입니다. 따라서 일반적으로 평행하게 여러 개의 변이 가능한 그래프를 작업하고 불변의 메시지로 정보를 교환하는 것이 더 효율적입니다. 즉, 그래프가 격리되어 있다는 것을 알면 외부 세계에 공개하지 않았다는 것을 알면 내가 생각할 수있는 가장 간결한 방식으로 작업을 수행하고 싶습니다. 그리고 그것은 일반적으로 데이터를 돌리는 것을 포함합니다. 그러나 데이터에서 이러한 작업을 마친 후에는 전 세계까지 데이터를 열고 싶습니다. 데이터가 변한 경우 일반적으로 약간 긴장하는 시점입니다. 프로그램의 다른 부분이 데이터를 손상시킬 수 있기 때문에 상태는 무효가됩니다. 세상을 여는 후에는 데이터가 종종 평행의 세계로 들어가기 때문입니다.

따라서 실제 병렬 프로그램은 일반적으로 데이터 그래프가 결정적인 단일 스레드 작업에 사용되는 영역을 가지고 있습니다. 단순히 외부에 알려지지 않기 때문에 다중 스레드 작업에 관여 할 수있는 영역 (데이터를 조작하지 않으면 데이터를 공급하는 것만으로도). . 이러한 멀티 스레드 부품 동안 우리는 절대 변경하기를 원하지 않습니다. 불일치 데이터보다 구식 데이터에서 작업하는 것이 좋습니다. 불변성의 개념으로 보장 할 수 있습니다.

그로 인해 간단한 결론을 내 렸습니다. 저에게 진짜 문제는 내가 익숙한 프로그래밍 언어 중 비가 아니라고 말할 수 있다는 것입니다. "이 시점 이후 에이 전체 데이터 구조는 불변이 될 수 없다" 그리고 "이 불변의 데이터 구조의 변이 가능한 사본을 여기에서 알려주세요. 돌연변이 가능한 사본 만 볼 수 있는지 확인하십시오.". 지금은 준비된 비슷하거나 비슷한 것을 뒤집어서 직접 보장해야합니다. 우리가 컴파일러를 지원할 수 있다면, 비트를 뒤집은 후에 어리석은 일을하지 않았다는 것을 보장 할뿐만 아니라 실제로 컴파일러가 이전에 할 수없는 다양한 최적화를 수행하는 데 도움이 될 수 있습니다. 또한 - 언어는 여전히 필수 프로그래밍 모델에 익숙한 프로그래머에게 매력적일 것입니다.

요약합니다. IMHO 프로그램은 일반적으로 데이터 그래프의 불변 및 변이 가능한 표현을 모두 사용해야 할 좋은 이유가 있습니다.. 나는 데이터가되어야한다고 주장한다 기본적으로 불변 그리고 컴파일러는 그것을 시행해야하지만 우리는 사적인 돌연변이 표현의 개념, 자연스럽게 다중 스레딩이 도달하지 못하는 영역이 있기 때문에 가독성과 유지 가능성은보다 명령적인 구조화로부터 이익을 얻을 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top