Code Monkey home page Code Monkey logo

Comments (10)

mitchellwrosen avatar mitchellwrosen commented on July 30, 2024

Also, for what it's worth, I've had to define my own

newtype EventM' a = EventM' (EventM a)
  deriving (Functor, Applicative, Monad)

because EventM is a type synonym and thus cannot be partially applied in a type such as Auto EventM Event AppState.

from brick.

jtdaugherty avatar jtdaugherty commented on July 30, 2024

I've checked in some changes that address your second comment (making EventM a newtype).

As for the first bit: I don't know anything about the auto package so it isn't immediately obvious to me what changes in brick would make it easier to integrate with auto. I've taken a look at some different approaches to making halt do what you want, and although I agree making it "return immediately" would be nice, I don't know of any approaches that would work at present. The issue is that the fact that EventM can "halt" or "continue" is not related to the monad at all, but to the Next type that is required to be returned by event handlers. So to make the monad capable of returning immediately, the "halt/continue/suspend-and-resume" features would need to be merged into the monad. My experiments suggested that the EventM type would need to be tagged with the state type of the application to permit a "halt" operation to match the type of the state expected to be returned by the event handler (e.g. EventM s (Next s)). But I think that is pretty messy, and adding such a type variable infects more innocent code than I'd like (and requires the type variable to be added to other types that don't have anything to do with it).

Without more information I don't think I can embark on a refactoring. I'm happy to consider patches if you have ideas on how to implement this.

from brick.

mitchellwrosen avatar mitchellwrosen commented on July 30, 2024

I haven't looked at the internals at all, but an API that seems more natural might be something like

data EventF a where
    Halt :: EventF a
    Suspend :: IO s -> (s -> a) -> EventF a

instance Functor EventF where ...

newtype EventM a = FreeT EventF (ReaderT (Map Name Viewport) (StateT EventState IO)) a
  deriving (Functor, Applicative, Monad, MonadFree EventF, ...)

continue :: s -> EventM s
continue s = pure s

halt :: EventM a
halt = liftF Halt

suspend :: IO s -> EventM s
suspend action = liftF (Suspend action id)

-----

appHandleEvent :: s -> e -> EventM s
defaultMain :: App s e -> s -> IO ()

from brick.

jtdaugherty avatar jtdaugherty commented on July 30, 2024

Thanks for writing that up! halt needs to be modified to take a state parameter of type s since that's a requirement of the API. I'd also like to know whether there are any viable approaches that don't involve using free.

from brick.

mitchellwrosen avatar mitchellwrosen commented on July 30, 2024

Ah, it was just a suggestion to allow you to move the Next semantics from the return type into the monad, as you mention. What's wrong with free if I may ask?

Alternatively - you could perhaps expose the Next ADT in some public Internal module. That'd suffice for my use case, although again, I can easily work around the problem by e.g. returning Just MyState to indicate continue, and Nothing to indicate halt.

from brick.

mitchellwrosen avatar mitchellwrosen commented on July 30, 2024

Here's a brick/auto adapter module from some work on a reddit client if you want to take a look. It's a bit kludgy and likely going to change eventually.

https://github.com/mitchellwrosen/reddit-cli/blob/master/src/Brick/Auto.hs

from brick.

jtdaugherty avatar jtdaugherty commented on July 30, 2024

I'd like to avoid exposing the internals of halt, continue, and suspendAndResume since I'd like to hide the implementation details. My objection to free is due to not understanding it, not being able to find any tutorials that clearly motivate it in this case, and wanting to avoid seemingly heavier abstractions where lighter ones will suffice (thus my desire for evidence that it is essential to a solution). If you can fill me in on this, that would be helpful!

Here's some extra context: my intention with the existing flow control API was to provide a mechanism for (only) the top-level event handler with the expectation that details about how to manage and compose event handling and state mutation would be a matter of doing pure operations rather than building up a library of EventM actions. Put another way, I imagined that composition would be free because most event-handling code wouldn't be written in EventM at all. I imagined most of it would be pure (except for handleEvent) and that if an application has a more sophisticated notion of flow control, it could be implemented in any way necessary and embedded in (and translated to) the expectations of EventM. I never intended for EventM computations to be especially composable because of this mentality. This is also why I would shy away from using EventM in a "return-immediately" imperative programming style since in my experience it has the potential to obscure event-handling logic and resist refactoring.

Thanks for linking to that demo module! That helps illuminate what you're dealing with in the auto/brick interaction. I guess if it were me doing it (again, speaking from a position of ignorance on auto), going on what I said above, I wouldn't write the Auto values in terms of EventM. It seems like that's the root cause of the need to instrument the rest of the API with the ability to deal with the results of the auto computations.

from brick.

mitchellwrosen avatar mitchellwrosen commented on July 30, 2024

Makes sense, and I'm definitely exploring this "imperative-ish" game-loop type world myself for the first time in Haskell. In fact, looking back over my code, I'm not yet even using auto to its full potential, which is isolating stateful computations from each other. For that reason, I could have just used ordinary functions that mutate the global state... which is exactly what the original API is!.

For understanding free, I recommend some of Gabriel Gonzalez's posts such as this one.

from brick.

jtdaugherty avatar jtdaugherty commented on July 30, 2024

Since it's been a while on this issue: is this a show-stopping problem for anything you need to do?

If not, I'd like to close this since I'm not inclined to make the change. I looked into free and wrote some toy programs with it but I don't grok it well enough to feel comfortable integrating it into a core part of my library.

from brick.

mitchellwrosen avatar mitchellwrosen commented on July 30, 2024

Nope, it's not a show stopper by any means.

from brick.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.