3

I am attempting to build a CLI interface for a basic app using Haskell and the Brick package. In all examples I have seen (including the documentation), the handleEvent function has the following type signature, in order to tell Brick to continue or stop execution after the state is updated:

AppState -> BrickEvent n e -> EventM n (Next AppState)

However, for me, my compiler is saying that Next is not found (nor can I manually export it from the package it is meant to be in, Brick.Main). The same is true for the continue function used below.

Minimum reproducible problem:

Main.hs:

module Main where

import Brick.Main
import Brick.Types
import Graphics.Vty.Input.Events

data AppState = AppState deriving (Show, Eq)

handleEvent :: AppState -> BrickEvent n e -> EventM n (Next AppState)
handleEvent s e =
    case e of
        VtyEvent vtye ->
            case vtye of
                EvKey (KChar 'q') [] -> halt s
                _ -> continue s
        _ -> continue s

brick-test.cabal:

cabal-version:      2.4
name:               brick-test
version:            0.1.0.0

author:             AlexScriba
maintainer:         61542302+AlexScriba@users.noreply.github.com

extra-source-files: CHANGELOG.md

executable brick-test
    main-is:          Main.hs
    build-depends:    
      base ^>=4.14.3.0,
      brick >= 1.7,
      vty
    hs-source-dirs:   app
    default-language: Haskell2010

I have tried again in different projects and it seems not to work in any of them. Have also tried with different versions of brick.

Alex Scriba
  • 95
  • 1
  • 8

2 Answers2

5

You're looking at outdated documentation and examples. Look at the ones from the version of brick you're using instead. Next and continue were removed from brick in version 1.0. You now need a type like this for handleEvent instead: BrickEvent n e -> EventM n AppState (). And instead of continue s, you do return () now.

  • Thanks that seems to be correct. Given it is now returning () how do I pass changed state? – Alex Scriba May 05 '23 at 07:30
  • @AlexScriba Can you edit your question to include the way you were trying to do so before? – Joseph Sible-Reinstate Monica May 05 '23 at 13:39
  • 1
    @AlexScriba `EventM n AppState` is an instance of `MonadState AppState`, so you just use the usual mtl stuff, e.g. `modify` or `state`, or of course the `lens` combinators for doing monadic updates. – Daniel Wagner May 05 '23 at 14:20
  • @JosephSible-ReinstateMonica I am not sure what you mean by "trying to do it before", could you elaborate? – Alex Scriba May 08 '23 at 01:28
  • @AlexScriba What did your code to pass changed state look like when you wrote it against the old version of `brick`? Can you edit it into your question? Then I can give you the exact translation of it. – Joseph Sible-Reinstate Monica May 08 '23 at 02:41
  • @JosephSible-ReinstateMonica that is actually amazing! However this is my first time building a brick application, so there is no older version. I believe I have figured out ```lens``` and ```MonadState``` to handle state changes on the new design. I will add it to the original question. Thanks! – Alex Scriba May 08 '23 at 14:01
1

Based on answers useful answers, the problem was that the approach above is based on outdated documentation. The latest versions use MonadState to handle the state, recommending changing the state using lens package.

The changed code (using microlens):

import Brick.Main
...

import Lens.Micro.Mtl (use, (.=))
import Lens.Micro.TH (makeLenses)

data AppState = AppState { _example :: String }
makeLenses ''AppState    -- Make lens to 'example'

handleEvent :: BrickEvent n e -> EventM n AppState ()
handleEvent e = do
    eg <- use example    -- Use lens to get _example from state
    example .= "New String"    -- Set example field in state
    
    case e of
        VtyEvent vtye ->
            case stye of
                EvKey (KChar 'q') [] -> halt
                _other -> return ()
        _other -> return ()
Alex Scriba
  • 95
  • 1
  • 8