본문 바로가기

프로그래밍(TA, AA)/개발방법론

[프로그래밍] 함수형 반응형 프로그래밍

1. 함수형 반응형 프로그래밍

1.1. 프로젝트, 복잡도의 벽에 부딪히다.

1.2. 함수형 반응형 프로그래밍이란?

1.3. FRP가 적합한 분야와 현재 상황

1.4. 대화형 애플리케이션(이벤트란?)

1.5. 상태 기계 분석의 어려움

1.6. 버그 없는 대화형 애플리케이션

1.7. 리스너는 이벤트 처리의 기둥.

1.8. 리스너의 여섯가지 문제점

1.9. 그냥 리스너만 고쳐서 사용하지 않는 이유

1.10. 재시작 그리고, 상태가 문제되는 이유

1.11. FRP의 장점: 복잡도 다루기

1.12. FRP는 어떻게 동작하는가 (FRP 프로그램의 생애 주기)

1.13. 패러다임 전환 (패러다임, 패러다임 전환)

1.14. 의존성 관점에서 생각하기.

1.15. 선언적으로 생각하기 (이 프로그램은 무엇인가)

1.16. FRP, 개념적 이해 vs 조작적 이해

1.17. 함수형 프로그래밍을 이벤트 기반 코드에 적용하기.


리스너와 콜백에는 많은 문제가 있다.

FRP는 상태기계와 리스너 또는 콜백을 대치한다.

FRP는 합성성이라는 수학적 특성을 통해 복잡도를 다룬다.

시퀀스라는 관점보다 의존관계라는 관점에서 생각하는 것이 더 낫다.

FRP 코드에는 방향성 그래프와 같은 구조가 들어있다. FRP 엔진은 그 그래프로부터 실행 순서를 만들어 낸다.

FRP는 선언적 프로그래밍 방식을 사용한다. 이는 프로그램이 어떤 일을 하는가보다는 어떤 것이 되어야 하는가에 관심을 갖는 것이다.

FRP는 근복적으로 어떤 것이다. 그래서 FRP는 발견된 것이지 발명된 것이 아니다.

FRP에서는 함수형 프로그래밍을 이벤트 기반 로직을 작성하기 위한 메타 언어로 사용할 수 있다.




2. FRP의 핵심

2.1. 스트림 타입: 이벤트의 흐름

2.2. 맵 기본 요소: 값 변환하기 (스트림 변환하기)

2.3. FRP 시스템의 구성요소 (기본 연산 조합, I/O와 로직 분리)

2.4. 참조 투명성

2.5. Cell 타입: 시간에 따라 변하는 값 (스트림이나 셀을 사용하는 이유, 상수 기본 연산, 셀 매핑하기)

2.6. merge 기본 연산: 스트림 합치기 (동시 이벤트, merge의 컬렉션 버전, merge가 어떻게 작동하나)

2.7. hold 기본 연산: 셀의 상태 유지하기

2.8. snapshot 기본 연산: 셀의 값 캡쳐하기

2.9. hold와 snapshot으로 루프를 만들어 누적기 구현 (전방 참조, 명시적 트랜잭션 안에서 FRP 구성, 누적기 코드, snapshot이 관찰하는 값이 새값일까, 이전 값일까?)

2.10. filter 기본 연산: 원하는 경우에만 이벤트 전달

2.11. lift 기본 연산: 셀 조합하기

2.12. never 기본 연산: 결코 발사되지 않는 스트림

2.13. 참조 투명성 관련 권장 사항

2.14. FRP 컨닝 페이퍼


스트림은 이벤트의 흐림이며, 각 이벤트는 페이로드 값으로 구성된다. 이벤트가 발생한 것은 스트림이 발사되었다고 말한다. 스트림을 부르는 다른 이름으로는 이벤트, 이벤트 스트림, 관찰 가능, 시그널 등이 있다.

map은 주어진 함수에 따라 스트림이나 셀에 있는 값을 변경한 새로운 이벤트나 셀을 만들어내는 기본 연산이다.

두 스트림에 대해 merge를 적용하면 두 입력 스트림에서 발생하는 이벤트를 조합한 새ㅑ로운 스트림을 얻을 수 있다.

동일한 트랜잭션 안에서 벌어지는 두 이벤트는 동시에 발생한 것이다.

셀은 시간에 따라 변하는 값을 포함한다. 셀의 다른 이름으로는 행동, 프로퍼티, 시그널 등이 있다.

hold는 초깃값을 가지고 셀을 만드럭나, 스트림에서 발된 값으로 셀의 값을 갱신한다.

셀과 스트림이 있다면 snapshot은 스트림이 발사된 순간의 셀 값을 캡처하고, 인자로 받은 함수를 가지고 스트림의 값과 셀의 값을 조합해준다.

filter를 사용하면 기존 스트림의 이벤트 중 일부만을 포함하는 새로운 스트림을 만들 수 있다. 이때 새 스트림에 이벤트를 포함시킬지 여부는 Boolean 값을 반환하는 predicate 함수가 결정한다.

lift에 둘 이상의 입력값에 대해 작용하느 함수를 넘기고, 몇개의 셀을 넘긴다. 그러면 lift가 그 함수를 사용해 모든 셀의 값을 합성한 새로운 셀을 돌려줄 것이다.

never는 결코 발사되지 않는 스트림을 말한다.

constant는 상숫값이 들어있는 셀을 만든다.

FRP 기본 연산에 넘기는 함수는 반드시 참조 투명해야 한다. 그 함수는 인자로 받는 값과 반환값을 제외하면 외부 세계에 의해 영향을 받거나, 외부 세계에 영향을 끼쳐서는 안된다.

소듐에서는 한 트랜잭션 안에서 갱신된 셀의 값을 다음 트랜잭션을 시작하기 전까지 볼 수 없다. 다른 FRP 시스템에서는 다른 정책을 사용할 수도 있다.





....


5. 새로운 개념

5.1. 전설의 폰노이만 기계를 찾아서 (느린 이유? 캐시 때문에, 이것이 FRP와는 어떤 관계일까?)

5.2. 합성성 (복잡성이 제어를 벗어날때, 환원주의와 엔지니어링, 합성성은 더이상 선택사항이 아님)

5.3. 합성성 부족을 보여주는 예 (객체지향 방식에서 합성성이 부족한 이유는?)

5.4. 합성성: 모든 종류의 버그 없애기

5.5. 불변값 사용 (불변 데이터 구조)

5.6. 의도의 명확성

5.7. 저렴한 추상화의 결과


6. 웹에서의 FRP

6.1. RxJS

6.2. Observable

6.2.1. 뜨거운 Observable과 차가운 Observable

6.2.2. 상태를 어떻게 관리할 것인가?

6.2.3. scan()을 사용한 상태가 있는 누적기

6.2.4. withLatestFrom()으로 가장 최근의 Observable 값 가져오기.

6.3. RxJS, Kefir.js, Flapjax에서 상태 유지하기

6.3.1. startWith()로 BehaviorSubject 줄여쓰기

6.3.2. Kefir.js에서 같은 작업 수행하기

6.3.3. 그리고 이제 Falpjax

6.4. combineLatest로 두 Observable의 마지막 상태 얻기

6.4.1. combineLatest의 작은 오류

6.4.2. merge는 합성적이지 않다.

6.7. RxJS/소듐 치트 시트

6.8. 정적 타입 지정을 선호


...


8. 조작적인 기본 연산

8.1. FRP 코드와 프로그램의 나머지 부분 연결하기

8.1.1. 스트림에 데이터 보내고 Listen하기

8.1.2. 단일 트랜잭션 안에서 여러번 send()하기

8.1.3. 셀에 데이터 보내고 Listen하기

8.1.4. 스레딩 모델과 콜백 요구사항

8.2. 지연 연산으로 루프 문제 해결하기

8.3. 트랜잭션

8.3.1. 명시적 트랜잭션 안에서 FRP 로직 만들기

8.4. 셀에서 updates나 value를 사용해 스트림 얻기

8.4.1. updates와 value

8.5. split 기본 연산으로 새로운 트랜잭션 컨텍스트 만들기

8.5.1. 한 이벤트를 새로운 트랜잭션으로 미루기

8.5.2. 같은 트랜잭션에서 만남

8.6. 규모 확장 가능한 대상 지정


9. 연속적인 시간

9.1. 시간을 래스터화하기

9.2. 시간 함수로 위치 표현하기

9.3. 시간 측정하기


10. 패러다임

10.1. 전통적인 상태 기계 vs FRP vs 액터 모델


11. 실전 프로그래밍

11.1. I/O 다루기

11.1.1. FRP에서의 오류 처리

11.1.2. I/O 액션 실행하기

11.1.3. 애플리케이션 하나로 모으기

11.2. Promise/Future

11.2.1. Promise를 사용하는 지도 뷰어

11.2.2. 스파크 숙어를 사용해 I/O 시작하기

11.3. 분산처리

11.3.1. 일관성 희생하기

11.3.2. 네트워크 연결을 통해 전달되는 스트림


...


14. 기존 프로젝트에 FRP 추가하기

14.1. FRP가 도움되는 분야

14.2. 불변 데이터 구조로 바꾸기

14.3. 콜백을 대체하는 스트림

14.3.1. 함정: 리스너 안에서는 send() 할 수 없다.

14.3.2. 올바른 덩어리 크기 정하기

14.4. 큰 트랜잭션 안에서 프로그램 초기화하기

14.5. 정션/클라이언트 레지스트리 사용으로 확장성 모듈 만들기

14.6. 셀이 변경가능한 변수를 대치할 수 있다




 기본 요소

 소듐(Java)

 RxJS(JS)

 리액트FX(Java)

 Stream

 Stream

 Rx.Observable

 EventStream

 Cell

 Cell

 Rx.BehaviorSubject

 Val

 never

 new Stream()

 Rx.Observable.of()

 new EventStreamBase()

 constant

 new Cell(i)

 Rx.Observable.of(i)

 Val.constant(i)

 map(S)

 s.map(f)

 s.map(f)

 s.map(f)

 map(C)

 c.map(f)

 c.map(f)

 c.map(f)

 merge

 s1.orElse(s2)

 s1.merge(s2)

 s1.merge(s2)

 EventStreams.merge(s1, s2)

 hold

 s.hold(i)

 var c = new

 Rx.BehaviorSubject(i);

 s.subscribe(c);

 Val.wrap(s.toBinding(i))

 snapshot

 s.snapshot(c, f)

 s.withLatestFrom(c, f)

 c.emitOn(s)

 filter

 s.filter(f)

 s.filter(f)

 s.filter(f)

 lift

 c1.lift(c2, f)

 c1.combineLatest(c2, f)

 Val.combine(c1, c2, f)

 sample

 c.sample

 

 c.get()

 switch

 Cell.switchS()

 Cell.switchC()

 s.flatMapLatest(f)

 s.flatMap(f)

 accum

 s.accum(i, f)

 s.scan(i, f)

 s.accumulate(i, f)

 listen

 s.listen(h)

 c.listen(h)

 s.subscribe(h)

 s.subscribe(h)

 send

 StreamSink / ss.send(a)

 CellSink / cs.send(a)

 Rx.Observable.create(f)

 new EventSource<>() / s.push(a)