Lobsters

Making a GTK application in Haskell, part 1

Haskell로 GTK 애플리케이션 만들기 1부

Haskell, GTK 4, libadwaita로 할 일 목록 앱을 만드는 연재의 첫 편입니다. haskell-gi로 GTK 바인딩을 사용하고 Elm Architecture의 Model-View-Update 구조를 적용해 상태와 사용자 인터페이스를 분리합니다.

AI 요약

Haskell 개발자를 대상으로 GTK 4와 libadwaita를 사용해 할 일 목록 애플리케이션을 만드는 연재의 첫 편입니다. 예제 코드는 애플리케이션 창을 띄우는 데서 출발해 상태 모델, 메시지 처리, 위젯 조립, GTK 이벤트 루프 연결까지 다룹니다. 글쓴이는 설명에 필요한 부분을 중심으로 코드를 제시하며, 전체 프로젝트는 GitHub 저장소에서 확인할 수 있다고 안내합니다.

GTK 4와 libadwaita

libadwaita는 GNOME의 디자인 언어와 Human Interface Guidelines(HIG)를 반영한 GTK 컴포넌트 라이브러리입니다. 글에서는 접근성과 스타일 외에도 데스크톱 테마가 바뀔 때 색상을 런타임에 조정하는 기능, 다양한 화면 크기에 대응하는 반응형 설계를 예로 듭니다. Haskell 쪽에서는 GTK 라이브러리 바인딩을 자동 생성하는 haskell-gi를 사용합니다. 이 도구는 C API와 연결되는 형태로 Haskell 인터페이스를 제공합니다.

첫 예제는 Adw.Application을 만들고 activate 신호에 핸들러를 연결합니다. 핸들러에서는 Adw.HeaderBar와 Adw.ToolbarView를 만든 뒤 Adw.ApplicationWindow에 제목과 기본 크기 480×640을 설정합니다. 마지막으로 창을 화면에 표시하고 GTK 애플리케이션 루프를 실행합니다.

Model-View-Update로 상태와 동작 표현하기

글은 Elm Architecture(TEA)의 세 요소인 Model, View, Update를 GTK 프로그램 구조에 적용합니다. Model은 애플리케이션 상태를 담고, View는 상태를 GTK 사용자 인터페이스로 바꾸며, Update는 메시지를 받아 상태를 갱신합니다. 사용자 동작은 Message 합 타입으로 표현하고, Update는 새 Model과 함께 실행할 작업인 Effect 목록을 돌려줍니다.

예제의 Model은 Todo를 TodoId 키로 저장하는 Map과 다음 ID를 담습니다. Todo에는 ID, 제목, 완료 여부가 들어갑니다. 메시지에는 할 일을 추가하는 Add와 완료 상태를 바꾸는 SetDoneStatus가 있습니다. Add는 입력 문자열의 앞뒤 공백을 제거하고, 빈 문자열이면 상태를 바꾸지 않습니다. 유효한 입력이면 다음 ID를 부여해 새 Todo를 추가합니다. 완료 상태 변경은 Map.adjust로 대상 항목을 갱신합니다.

두 동작은 공통 함수 withTodos를 거칩니다. 변경 전후의 Todo 목록이 같으면 Effect를 만들지 않습니다. 목록이 달라지면 디스크 저장을 뜻하는 Save 효과에 현재 Todo 목록을 담아 반환합니다. GHCi 예제에서는 할 일을 추가하거나 완료 상태를 바꿀 때 Save가 생성되고, 이미 완료된 항목을 다시 완료 처리하면 빈 효과 목록이 나옵니다.

GTK 위젯으로 화면 구성하기

View는 메시지를 전달하는 dispatch 함수와 현재 Model을 받아 GTK 위젯을 반환합니다. 입력용 Adw.EntryRow에서 입력 완료 신호를 받으면 텍스트를 읽어 Add 메시지를 보냅니다. 목록에는 할 일마다 Adw.ActionRow를 추가합니다. 글은 EntryRow와 ActionRow를 담는 Gtk.ListBox, 세로 배치와 여백을 맡는 Gtk.Box, 화면 폭을 제한하는 Adw.Clamp, 스크롤을 제공하는 Gtk.ScrolledWindow를 조립합니다. ToolbarView에는 상단 헤더와 하단 푸터도 붙이며, 푸터에는 항목 수를 표시합니다.

Runtime에서 GTK와 연결하기

Runtime은 Model-View-Update를 애플리케이션에 연결합니다. Model은 IORef에 저장합니다. dispatch는 GLib.idleAdd를 사용해 메시지 처리를 GTK 실행 루프의 기본 우선순위 작업으로 예약하고, step은 현재 상태를 읽어 update를 호출합니다. 새 상태를 IORef에 기록한 뒤 View를 다시 만들고, 새 위젯을 창의 콘텐츠로 설정합니다. 글은 이 편에서 도메인 로직과 화면 갱신 흐름을 구성하며, 다음 편에서 할 일 목록 기능을 더할 예정이라고 마무리합니다.

원문: Floreal Technologies / 번역·요약: Trawling