Reflex (작성 예정)

Posted on October 29, 2023

Reflex 공식 사이트
Reflex 공식 문서

앱 만들기를 빠르게 시작하려면 Obelisk를 쓰든가, reflex-platform을 씁니다.

Obelisk

obsidiansystems/obelisk
고퀄의 웹, 모바일 앱을 Reflex를 써서 매우 빠르게 만들 수 있다고 합니다. 아직은 제대로 안 써봐서 얼마나 빠르게 만들 수 있을까 싶습니다. 같은 하스켈 코드로 Web, iOS, Android, MacOS, Linux에서 돌아가게 만들 수 있다고 하니, 일단 눈이 갑니다.

명령행에서 쓰는 CLI툴입니다.

Reflex Platform

Reflex Platform

Reflex를 쓰는 하스켈 패키지를 다양한 플래폼에서 돌아가게 빌드할 수 있는 엄선된curated 패키지 세트 및 도구 입니다. 닉스 패키지 매니저로 돌릴 닉스 표현식 모음과 ghc, ghcjs를 쓰기 위한 스크립트 모음이라 보면 됩니다.

  1. 엄선된 패키지와 도구: Reflex Platform의 핵심 패키지는, 서로 함께 돌리는 테스트를 마쳤습니다.
  2. 바이너리로 받을 수 있어(public cache가 있습니다.), 소스에서부터 빌드할 필요가 없습니다.
  3. 하스켈 생태계 바깥쪽의 요소(C라이브러리 같은 것들)까지도 닉스가 의존성을 잠궈놨습니다.
  4. 크로스 플래폼. 모바일(iOS, Android) 웹(Javascript), 데스크탑(리눅스, 맥OS)에서 돌아갑니다.
  5. 쉽게 개발하도록 도와주는 도구들을 포함하고 있습니다. (hoogle 서버도 포함되어 있어 로컬에서 돌릴 수 있습니다.)

GHCJS로 컴파일하면, 메모리를 엄청 잡아 먹습니다. 최소 8GB, 권장 16GB라 합니다.
TMPDIR 디렉토리도, /nix/store도 꽤 잡아 먹습니다.

공부용이나, 작은 프로젝트는 try-reflex 스크립트를 돌려서 환경을 잡으면 되는데, 큰 프로젝트는 cabal을 쓰는 게 좋다 합니다. cabal로 환경 잡기

try-reflex를 실행하는데, 세 시간이 넘게 걸리고, 디스크 용량은 거의 30GB를 먹었습니다. 환경마다 다르겠지만, 엔간한 장비에선 긴 시간이 필요한 작업 같습니다.

실행 후 한참을 기다렸는데, 믿었던 닉스가 No space left on device 오류를 뱉습니다. 설치할 곳의 공간은 여유가 있는데도 계속 오류가 나서, 찾아 보니 닉스가 쓰는 임시 폴더 용량이 문제였습니다.
export TEMP=/other/sufficientDir 혹은
export TMPDIR=/other/sufficientDir을 했는데도
임시 디렉토리를 사용하는 곳이 바뀌지 않았습니다. 닉스가 딱히 시스템 수준의 환경 변수를 읽어가지 않나 봅니다. 시스템 수준의 환경 변수가 아닌 데몬을 위한 환경 변수를 잡아주어 성공했습니다. 데비안6.1.66-1 (2023-12-09) 환경.

sudo vim /etc/systemd/system/nix-daemon.service

[Service]
...
Environment=TMPDIR=/other/sufficientDir

위와 같이 추가하고

sudo systemctl daemon-reload
sudo service nix-daemon restart

※ NTFS 파티션에 잡으니 cp: perserving times for …: Operation not permitted 오류가 납니다.

Reflex Basics

Reflex Basics

reflex
콜백 스타일을 쓰지 않고, side effect도 없이 인터랙티브 프로그램을 만듭니다. 조합compositable 가능한 이벤트시간에 따라 변하는 값을 써서 인터랙티브 시스템을 순수 함수로 표현합니다. DOM 생성 코드와는 무관합니다. reflex는 reflex-dom의 기반이긴 하지만, 꼭 웹 관련 앱이 아니더라도 FRP 아키텍처로 구현할 때 쓸 수 있습니다.

reflex-dom-core와 reflex-dom
DOM 위젯, 웹 소켓, XHR 요청을 만들기 위한 API를 제공합니다.

이론에 대한 설명은 딱히 같이 하지 않아, Reflex만 보는 분들은 다른 쪽(FRAN, Yampa, reactive-banana, …) 문서들을 참고해야겠습니다.

Behavior
시간에 따라 변하는 값을 위한 컨테이너. 샘플링할 수는 있지만, 자신이 변한다고 외부에 알릴 방법은 없습니다.

Behavior t a

모든 시간에 값이 존재해야 하는데, 만일 그렇지 않은 값을 Behavior로 모델링 한다면 Behavior t (Maybe a)를 써야 합니다. Behavior 값들은 tagattach 함수를 써서 Event로 태깅할 수 있습니다. 처음 생성할 때 sample 함수를 쓰면 위젯 안에서 샘플링될 수 있습니다.

Event

Event t a

버튼 클릭 Event t ()
키 누름 Event t Char

다른 프레임워크에서 이벤트 네트워크라 부르는 걸, 여기선 이벤트-전파-그래프라 부르는 것 같습니다. 외부 값(외부 이벤트)을 이벤트-전파-그래프에 넣을 때는 newTriggerEvent IO 액션을 씁니다.

newTriggerEvent :: TriggerEvent t m => m (Event t a, a -> IO ())

Dynamic
Event와 Behavior를 튜플에 담아 둔 것

DOM API는 기본적으로 push-기반입니다. 그래서 Behavior를 쓸 곳에 Dynamic을 쓰는 경우가 많습니다.

Dynamic값에 updated를 적용해서, 값이 변했을 때 이벤트를 얻을 수 있습니다.

updated :: (Reflex t) => Dynamic t a -> Event t a

타임라인 t는 FRP 컨텍스트와 별 개입니다. 단일 프로그램이 Reflex를 여러 컨텍스트에서 돌릴 경우 꼬이지 않게 해줍니다.?

Reflex-DOM 앱의 아키텍처

위젯과 위젯들을 연결하는 접착glue 코드로 구성됩니다. 위젯은 Event나 Dynamic value에 따라 컨텐츠를 수정할 수 있는 능력을 가진 DOM 구조의 무언가로 볼 수 있습니다. 이벤트를 발생시키는 input field 같은 구조들도 있습니다. 위젯들은 마우스 클릭같은 사용자 인터랙션에 반응할 수 있습니다. (이 걸 위젯이 마우스 클릭을 캡처한다고 말하기도 합니다.)

DOM 생성

“오브젝트” 트리
모나드 DomBuilder로 DOM 생성 작업을 합니다.

ghcjs
ghc같은 컴파일러

ghcjs-dom
DOM과 웹API와 쓰일 인터페이스 API를 제공하는 라이브러리

Webkit

KDE의 KHTML과 KJS에 파생된 웹 컨텐트 엔진. Apple 사파리 브라우저에 쓰입니다. HTML, SVG, XML 등을 디스플레이할 때 쓰입니다. DOM, XMLHttpRequest, XSLT, CSS, Javascript/ECMAscript 등을 지원합니다.

Github 계정이 없는 분은 메일로 보내주세요. lionhairdino at gmail.com