Haskell을 처음 접하는 사람들이 주목 한 가장 명백한 혁신은 외부 세계와의 의사 소통과 관련된 불순한 세계와 순수한 계산 및 알고리즘 세계가 분리되어 있다는 것입니다. 빈번한 초보자 질문은 "내가 제거 할 수있는 방법이다 IO
, 즉, 변환을 IO a
에 a
?" 이를 수행하는 방법은 모나드 (또는 다른 추상화)를 사용하여 IO 및 체인 효과를 수행하는 코드를 작성하는 것입니다. 이 코드는 외부 세계에서 데이터를 수집하고, 모델을 생성하고, 순수한 코드를 사용하여 일부 계산을 수행하고 결과를 출력합니다.
위의 모델에 관한 한, IO
모나드 에서 GUI를 조작하는 데 아무런 문제가 없습니다 . 이 스타일에서 발생하는 가장 큰 문제는 모듈을 더 이상 구성 할 수 없다는 것입니다. 즉, 내 프로그램에서 명령문의 전역 실행 순서에 대한 대부분의 지식을 잃습니다. 이를 복구하려면 동시 명령형 GUI 코드와 유사한 추론을 적용해야합니다. 한편, 비 GUI 코드가 정확하지 않은 경우 IO
모나드 >==
연산자 의 정의 (적어도 하나의 스레드 만있는 경우) 때문에 실행 순서가 분명 합니다. 순수한 코드의 경우 성능을 높이거나 평가 결과를 피하기 위해 코너 케이스를 제외하고는 전혀 중요하지 않습니다 ⊥
.
콘솔과 그래픽 IO의 가장 큰 철학적 차이점은 전자를 구현하는 프로그램이 일반적으로 동기식 스타일로 작성된다는 것입니다. 이것은 신호와 다른 열린 파일 디스크립터를 제외하고 하나의 이벤트 소스 만 있기 때문에 가능합니다 stdin
. 일반적으로 바이트 스트림이라고 합니다. GUI는 본질적으로 비동기 적이며 키보드 이벤트 및 마우스 클릭에 반응해야합니다.
기능적인 방식으로 비동기 IO를 수행하는 일반적인 철학을 FRP (Functional Reactive Programming)라고합니다. ReactiveX 와 같은 라이브러리와 Elm과 같은 프레임 워크 덕분에 최근에는 불완전하고 작동하지 않는 언어로 많은 관심을 받았습니다 . 간단히 말해서 GUI 요소 및 기타 항목 (예 : 파일, 시계, 알람, 키보드, 마우스)을 이벤트 스트림을 발생시키는 "관찰 가능"이라고하는 이벤트 소스로 보는 것과 같습니다. 이러한 이벤트는 다음과 같은 친숙한 연산자를 사용하여 결합 map
, foldl
, zip
, filter
, concat
, join
, 등, 새로운 스트림을 생성 할 수 있습니다. 이것은 프로그램 상태 자체가 scanl . map reactToEvents $ zipN <eventStreams>
프로그램에서 볼 수 있기 때문에 유용합니다 . 여기서 프로그램에서 N
고려한 관측 가능 수와 같습니다.
FRP 옵저버 블을 사용하면 스트림의 이벤트가 제 시간에 정렬되므로 작곡 성을 복구 할 수 있습니다. 그 이유는 이벤트 스트림 추상화로 모든 관찰 가능 항목을 블랙 박스로 볼 수 있기 때문입니다. 궁극적으로 연산자를 사용하여 이벤트 스트림을 결합하면 실행시 로컬 순서가 다시 결정됩니다. 이로 인해 Haskell의 모든 함수가 참조 적으로 투명 해야하는 방식과 유사하게 내 프로그램이 실제로 의존하는 변수에 대해 훨씬 더 정직해야합니다. 프로그램의 다른 부분에서 데이터를 가져 오려면 명시 적이어야합니다. 내 기능에 적합한 유형을 선언하십시오. (불순한 코드를 작성하기위한 도메인 별 언어 인 IO 모나드는이를 효과적으로 우회합니다)