2016-06-06 1 views
0

에 내 질문에 내가 tutorial을 읽었으며 반응 프로그래밍 방법에 대해 배우고, 실험하고있는 반응성 패키지 https://github.com/JuliaLang/Reactive.jl직관적 동작은 Reactive.jl

에 관한 것이다. 나는 다음과 같은 코드를 시도하고 그것은 예상대로 작동 : 인쇄되는 590 (610) betwwen

using Reactive 

x = Signal(100) 
z = map(v -> v + 500, x; typ=Int64, init=500) 
dar = rand(90:110,10) 

for i in dar 
    push!(x, i) 
    println(value(z)) 
end 

이 예상대로, 리드 (10)에 임의의 숫자 :

500 
591 
609 
609 
605 
593 
602 
596 
590 
594 

지금까지 너무 좋아. 이제, 각각의 갱신 이후에 신호 (Z)의 출력을 수집 할 가정 벡터 C로 말 :

using Reactive 

x = Signal(100) 
z = map(v -> v + 500, x; typ=Int64, init=500) 
dar = rand(90:110,10) 
c = Vector() 

for i in dar 
    push!(x, i) 
    push!(c, value(z)) 
end 

그러나 대신 벡터의 590과 610 사이의 열 난수를 갖는 C, C를 함유하는 벡터는 값 500 번 열 번 :

10-element Array{Any,1}: 
500 
500 
500 
500 
500 
500 
500 
500 
500 
500 

이 동작이 내가 반작용 프로그래밍에 대해 이해하지 못하는 것이 원인인지 이해하려고합니다. 루프에 을 결합하면신호은 아니오입니까? 이 문제의 원인에 대한 통찰력을 주셔서 감사합니다.

참고로 IJulia 노트북에서 Julia 0.4.5를 사용하고 있습니다.

+0

대답이 아니지만 'push!'사이에'yield()'를 추가하는 것은 최소한의 변화로 작동합니다. 'z' 값의 업데이트는 다른 작업에서 발생합니다. –

+0

'yield()'대신에 신호에'push! '뒤에'Reactive.run_till_now()'를 사용하십시오. 이 팁은 https://github.com/JuliaLang/Reactive.jl/issues/99 –

+0

에서 작동합니다. 작동합니다. 감사합니다. 이것은 이런 식으로 일어날 것 같지 않지만 그것은 더 의미가 있습니다. – pyrex

답변

2

줄리아의 Reactive.jl 라이브러리는 줄리아의 Reactive programming을 허용하도록 설계되었습니다. 요점은 신호 만 반응한다는 것이며 신호는 독립적이거나 다른 신호에 의존합니다. 이 예에서 x은 독립 신호이며 신호의 기본 업데이트는 push!을 호출합니다. zx에 종속 신호이므로 x이 변경되면 자동으로 업데이트됩니다.

이 두 가지 신호 만 있습니다. cVector()으로 정의되어 있습니다.이 신호는 신호가 아니지만 줄리아의 정상적인 배열입니다. 따라서 실행되는 모든 코드는 모든 비 반응 언어와 같이 한 번만 수행됩니다. z 여전히 코드에서 500 인해 init=500의 기본 값을 유지함으로써 코드가 먼저 실행되면 따라서

for i in dar 
    push!(x, i) 
    push!(c, value(z)) 
end 

는 한 번만 c에 할당합니다. 이것은 직관적 인 의미를가집니다. 사실 z에, 우리는 줄리아의 기본 동작을 무효로 만들었 때문에, c 경우 변경, 이것은

그래서 우리는 어떻게 z가 수행 할 때마다 c 업데이 트를해야합니까 ... 휘발성 때문에 바람직하지 않다? 올바른 방법은 리 액티브 프로그래밍을 항상 사용하는 것이므로 c은 종속 신호 z이어야합니다. cz의 상태를 유지하므로 리 액티브 프로그래밍의 올바른 구문은 foldp이며 "이전 값을 폴드합니다"를 의미합니다.

작동하는 코드는 다음 -

using Reactive 

x = Signal(100) 
z = map(v -> v + 500, x) 
c = foldp((acc, value) -> push!(acc, value), Int[], z) 

for i in rand(90:110, 10) 
    push!(x, i) 
    yield() #Can also use Reactive.run_till_now() 
    println(value(z)) 
end 

@show value(c) 

너무 초기 값을 원하는 경우, 그래서 당신은 선택에 의해 초기 값을 제외한 z 이전의 모든 값의 배열 (수 c을 얻을 것이다 쉽게 할 수 있습니다). 리 액티브 프로그래밍은 유사한 코드 복잡성을 유지하지만 리액션 기능을 추가합니다. 따라서 코드를 더 우아하고 쉽게 유지할 수 있습니다.

설명에 추천 된대로 yield() 또는 Reactive.run_till_now()을 사용하므로 설명을 생략합니다. 그러나 제 의견은 당신이 그렇게 할 필요가 있다면, 반응 프로그래밍을 올바르게 사용하지 않았거나 문제가 다른 패러다임에 더 잘 맞을 것이라는 것입니다.

이 난에 다음과 같이 쓸 수있다 : - 반응 부분은 자기 설명이다

using Reactive 

x = Signal(100) 

z = map(x) do v 
    result = v + 500 
    println(result) 
    return result 
end 

c = foldp(Int[], z) do acc, value 
    push!(acc, value) 
end 

for i in rand(90:110, 10) 
    push!(x, i) 
end 

@show value(c) 

알 수 있습니다. 이제 z은 업데이트 될 때마다 자체적으로 인쇄됩니다. 이는 필수적 대신 설명 적입니다. 업데이트가 비동기 일지라도 z에 대한 업데이트를 계속 캡처합니다. x으로 진행하는 명령형 코드는 그 자체로 모듈화 된 것입니다. 이 코드는 높은 수준의 스크립트 내부에 yield()과 같은 저수준의 루틴 전달 함수가 없어도 읽기 쉽고 읽기 쉽습니다.

+0

@ShaoWei 귀하의 상세하고 유익한 답변을 주셔서 감사합니다. 그렇게 철저히 설명 할 시간을내어 주셔서 감사합니다. – pyrex

+0

당신은 @pyrex입니다, Julia의 Reactive.jl은 아주 아름답습니다. 당신과 그 이야기를 나눌 수있어서 기쁩니다. –