2011-12-21 4 views
17

reactive-banana을 사용하는 프로그램에서 작업하고 있으며 기본 FRP 구성 요소로 내 유형을 구조화하는 방법을 알고 싶습니다.적용 위치 FRP의 동작 (및 다른 유형)

예를 들어, 내 실제 프로그램의 단순화 된 예는 다음과 같습니다. 내 시스템은 주로 위젯으로 구성되어 있습니다 - 내 프로그램에는 시간 경과에 따라 텍스트가 다릅니다.

나는

newtype Widget = Widget { widgetText :: Behavior String } 

을 가질 수 있지만, 나는 또한

newtype Widget = Widget { widgetText :: String } 

하고 난이 시간에 따라 변화하는 행동에 대해 이야기 할 때 Behavior Widget를 사용할 수 있습니다. 이것은 일을 "더 간단하게"하는 것으로 보이며, 위젯을 언팩하고 재 패키징하지 않고보다 직접적으로 Behavior 작업을 사용할 수 있음을 의미합니다.

반면 위젯은 실제로 위젯을 정의하는 코드에서 중복을 피하는 것 같습니다. 거의 모든 위젯이 시간에 따라 다르기 때문에 Behavior으로는 소수를 정의하는 경우가 있습니다. 보다 일관된 방식으로 다른 것들과 결합 할 수있게 해줍니다.

또 다른 예로, 두 표현을 사용하면 Monoid 인스턴스를 가질 수 있습니다. (내 프로그램에 하나 갖고 싶습니다.) 그러나 후자에 대한 구현은 더 자연 스럽습니다 (newoid에 monoid를 나열하십시오).

는 (내 실제 프로그램은 오히려 Behavior보다는 Discrete를 사용하지만, 그게 관련이 있다고 생각하지 않습니다.)

을 마찬가지로, 나는 2D 점을 표현하기 위해 Behavior (Coord,Coord) 또는 (Behavior Coord, Behavior Coord)를 사용해야합니까? 이 경우 전자는 명백한 선택처럼 보입니다. 그러나 게임에서 엔티티와 같은 것을 나타내는 5 개 요소의 레코드 일 때 그 선택은 명확하지 않은 것처럼 보입니다. 본질적으로

, 이러한 모든 문제가 아래로 감소 :

어떤 계층에서 나는 Behavior 유형을 적용해야, FRP를 사용하고 계십니까?

(같은 질문은 비록 낮은 수준으로, 너무 Event에 적용됩니다.)

답변

5

나는 가능한 한 많이 "변경 일을"분리 dflemstr's advice

  1. 에 동의합니다.
  2. "동시에 변경되는 항목"은 하나의 Behavior/Event으로 그룹화됩니다.

이러한 경험 법칙에 대한 추가 이유를 제공하고 싶습니다. 당신은 시간의 변화 값의 쌍 (튜플)을 표현하고 싶은

을 사용할지 여부를 질문은 :

질문은 다음으로 요약된다. (Behavior x, Behavior y) - 한쌍의 행동

b. Behavior (x,y) - 쌍의 동작은 다른 이상을 선호위한

이유

  • 이상의 B 있습니다.

    푸시 구동 구현에서는 동작 변경으로 인해 동작에 의존하는 모든 동작을 다시 계산합니다.

    이제 값이 해당 쌍의 첫 번째 구성 요소 인 x에만 의존하는 동작을 고려해보십시오. 변형 에서의 두 번째 구성 요소가 변경되면 동작이 다시 계산되지 않습니다. 그러나 변형 b에서 그 값이 두 번째 구성 요소에 전혀 의존하지 않는 경우에도 비헤이비어가 다시 계산됩니다. 다시 말해, 세분화 된 대 굵은 종속성에 대한 질문입니다.

    은 물론 조언 1. 인수이며,이 두 행동은 물론 조언 2.

    산출하는 동시에 변화하는 경향이 때 많은 중요성이 아닌 라이브러리 잘 제공 할 수있는 방법을 제공해야 변형 된 b에 대해서도 상관 관계가 없습니다. 리 액티브 바나나 버전 0.4.3부터, 이것은 불가능하지만, 지금 당장은 걱정하지 않아도됩니다. 푸시 구동 구현은 차후 버전에서 완성 될 것입니다.

  • b ( 이상).

    그 반응 바나나 버전 0.4.3을 보는 것은 당신이 한 행동에 모든 구성 요소를 넣어 경우에만 쓸 수있는 특정 프로그램이있다, 아직 dynamic event switching을 제공하지 않습니다. 표준 예제는 변수 인 개의 카운터 (즉, TwoCounter.hs 예제의 확장자)를 특징으로하는 프로그램입니다. 시간의 변화하는 값 목록으로 나타내야합니다.

    counters :: Behavior [Int] 
    

    동적 동작 컬렉션을 추적 할 방법이 아직 없기 때문에이를 표현해야합니다. 즉, 반응성 바나나의 다음 버전에는 동적 이벤트 스위칭이 포함됩니다.

    또한, 당신은 항상 내가 렌즈는 여기에 도움이 생각하지 않는다

    uncurry (liftA2 (,)) :: (Behavior a, Behavior b) -> Behavior (a,b) 
    
+1

'위젯'의 경우, 단 하나의 필드 만 갖는 것은 단순화가 아니었다. 내 실제 상황이므로 튜플이 필요 없다. 도움을 주셔서 감사합니다. 앞으로 매우 도움이 될 것입니다! 지금은 'Behavior'를 newtype에 넣을 것입니다. 나는 두 가지 대답을 모두 받아 들일 수 있었으면 좋겠다 :) – ehird

6

FRP 응용 프로그램을 개발할 때 사용하는 규칙은 다음과 같습니다

  1. 가로 "변경 일을"분리 가능한 한 많이
  2. "동시에 변경되는 항목"은 Behavior/Event으로 하나가됩니다.

이유는 (1) 사용하는 데이터 형식이 가능한 한 원시적 인 경우 추상 작업을 만들고 구성하는 것이 쉬워집니다.

이유는 설명한대로 Monoid 같은 인스턴스를 원시 형식으로 다시 사용할 수 있기 때문입니다.

Lenses을 사용하여 데이터 유형의 "내용"을 원시 값인 것처럼 쉽게 수정할 수 있으므로 추가 "래핑/래핑 해제"는 대부분 문제가되지 않습니다. (이 특정 렌즈 구현에 대한 소개는 this recent tutorial을 참조하십시오 : others)

이유는 불필요한 오버 헤드를 제거하기 때문입니다. 두 가지가 동시에 바뀌면 그들은 "똑같은 행동"을하기 때문에 그렇게 모델링되어야합니다.

에르고/TL; DR : 당신 때문에 (1)의 newtype Widget = Widget { widgetText :: Behavior String }를 사용한다, (2) (두 좌표 때문에 일반적으로 동시에 변경)의 때문에 당신은 Behavior (Coord, Coord)를 사용해야합니다.

+0

아무 문제없이 B을 변형에 변형 에서 변환 할 수 있습니다 -은'Monoid' 예제를 사용하려면, 그건 'f = liftA2 mappend'와 같은 것은'fab = Widget $ mappend (widgetText a) (widgetText b)'가됩니다. 틀림없이, 조합기를 들어 올리면이 고통이 완화 될 수 있습니다. 그러나,'Monoid' 예제를 참조하여 여러분이 무엇을 말하려고하는지 확신 할 수 없습니다.'Behavior String' 폼이 아닌'String' 폼의 인자가 될 것입니다. – ehird

+0

당신의 규칙은 아주 좋은 것처럼 들리지만, 저는 그것에 대해 좀 더 생각해야 할 것입니다. 게시 해 주셔서 대단히 감사합니다! 저는 다른 견해와 관점을 듣고 싶고 이후로는 아주 미묘한 질문이기 때문에이 대답을 받아 들일 수 없습니다. – ehird

+0

'위젯 (widget)'예에서는 '위젯 텍스트 (widgetText)'만 포함되어있어 쉽게 들리지 않습니다. '위젯 (Widget) '에 더 많은 가치가 있다면, 리프팅은 렌즈를 통해'행동 (Behavior) '을 해제하고 그런 식으로 작업을 수행하는 것보다 훨씬 더 복잡해집니다. – dflemstr