Chris Stryczynski

Software Developer / Consultant

Haskell Brick tutorial - written with GitChapter

Posted on: 03/06/2018

This project is written with https://github.com/chrissound/GitChapter, this means you are able to clone down the project from https://github.com/chrissound/Git-Chapter-Tutorial-for-Haskell-Brick, and hack along from each section where you see the following:

Git From Commit: 
02260c20f404d7aaa347fb16e4e750b129636929

Git Until Commit: 
106248bbb9cbddea04e0a03b97d2c45b5337c8ee

This time we’ll be looking at brick they also have an exellent guide written here: https://github.com/jtdaugherty/brick/blob/master/docs/guide.rst.

Simple start

Okay so far so good.

Lets get the simplest example we can:

We need to add two packages and the ghci-options threaded (using hpack instead of the usual cabl):

diff --git a/package.yaml b/package.yaml
index d3805a9..c74178e 100644
--- a/package.yaml
+++ b/package.yaml
@@ -6,8 +6,11 @@ build-type: Simple
 maintainer: Chris Stryczynski
 dependencies:
 - base >=4.10 && <4.11
+- brick
+- vty
 name: app
 version: '0.1.0.0'
 extra-source-files: ChangeLog.md
 author: Chris Stryczynski
 license: BSD3
+ghc-options: -threaded

And we start of with:

module Main where

import Brick
import Graphics.Vty.Attributes

type AppState = Int

app :: App AppState () String
app =
  App
  { appDraw = const []                          :: AppState -> [Widget String]
  , appChooseCursor =
      const . const Nothing                     :: AppState -> [CursorLocation String] -> Maybe (CursorLocation String)
  , appHandleEvent =
      (\appState _ -> Brick.continue appState)  :: AppState -> BrickEvent String () -> EventM String (Next AppState)
  , appStartEvent = return                      :: AppState -> EventM String AppState
  , appAttrMap = const (attrMap (defAttr) ([])) :: AppState -> AttrMap
  }

main :: IO ()
main = do
  let initialState = 5
  defaultMain app initialState >>= print

Now if we build and run the project we see:

stack exec app

Reading through this short section would be useful: https://github.com/jtdaugherty/brick/blob/5fdfaf327af12bc8f4e362a1a41d519f63d87248/docs/guide.rst#appdraw-drawing-an-interface so if we try do a simple “hello world” example:

diff --git a/src/Main.hs b/src/Main.hs
index e6c27fa..131532d 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -1,6 +1,7 @@
 module Main where
 
 import Brick
+import Brick.Widgets.Border
 import Graphics.Vty.Attributes
 
 type AppState = Int
@@ -8,15 +9,22 @@ type AppState = Int
 app :: App AppState () String
 app =
   App
-  { appDraw = const []                          :: AppState -> [Widget String]
+  { appDraw = appDraw'
   , appChooseCursor =
       const . const Nothing                     :: AppState -> [CursorLocation String] -> Maybe (CursorLocation String)
   , appHandleEvent =
-      (\appState _ -> Brick.continue appState)  :: AppState -> BrickEvent String () -> EventM String (Next AppState)
+      (\appState _ -> Brick.halt appState)  :: AppState -> BrickEvent String () -> EventM String (Next AppState)
   , appStartEvent = return                      :: AppState -> EventM String AppState
   , appAttrMap = const (attrMap (defAttr) ([])) :: AppState -> AttrMap
   }
 
+appDraw' :: AppState -> [Widget String]
+appDraw' _ = [
+    (str "Hello," <=> str "World!" <=> hBorder)
+  , hBox [str "                                              Woohoo"]
+  ]
+
+
 main :: IO ()
 main = do
   let initialState = 5

After building and executing:

Hmmm that seems a bit odd doesn’t it?

Comments

No comments, yet!

Submit a comment