Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why BotM has to end with an action? #41

Closed
cblp opened this issue Nov 25, 2020 · 7 comments
Closed

Why BotM has to end with an action? #41

cblp opened this issue Nov 25, 2020 · 7 comments

Comments

@cblp
Copy link

cblp commented Nov 25, 2020

It looks like ending BotM with pure NoAction is boilerplate. As well as handleAction NoAction = pure model.

So, an extra action is always issued.

And user Action is always ~ Maybe Action'.

At the same time, botAction allows for the absence of action with Maybe in its signature.

Is Eff really needed? How to send a message without an extra action?

@cblp
Copy link
Author

cblp commented Nov 25, 2020

I wrote some helpers for myself

    botAction :: Update -> Model -> Maybe (Maybe Action)
    botAction update model = Just <$> onUpdate update model

    botHandler :: Maybe Action -> Model -> Eff (Maybe Action) Model
    botHandler maction model =
      case maction of
        Nothing     -> pure model
        Just action -> onAction action model

(<#) :: model -> BotM a -> Eff (Maybe action) model
m <# b = withEffect (b $> Nothing) m

They don't help with extra iteration, but remove non-sense code.

@fizruk
Copy link
Owner

fizruk commented Nov 25, 2020

It looks like ending BotM with pure NoAction is boilerplate. As well as handleAction NoAction = pure model.

I agree, ergonomics might be slightly better, however I don't think using Nothing instead of NoAction is better.

At the same time, botAction allows for the absence of action with Maybe in its signature.

Ideally that Maybe should actually be something more sophisticated, e.g. Either UpdateParseError. So Nothing there does not have the same meaning as NoAction.

Is Eff really needed?

Eff ensures separation of "impure" BotM actions from pure model updates.

How to send a message without an extra action?

You can use the helper (<#) that you wrote, with Nothing or NoAction depending on your preference :)

@cblp
Copy link
Author

cblp commented Nov 25, 2020

Ideally that Maybe should actually be something more sophisticated, e.g. Either UpdateParseError. So Nothing there does not have the same meaning as NoAction.

Why? How can the framework handle this instead of user code? I can imagine type Action = Either UpdateParseError GoodData, but no -> Either UpdateParseError Action

Eff ensures separation of "impure" BotM actions from pure model updates.

But why [BotM action] instead of BotM ()?

Separation can be achieved through handleAction :: action -> model -> (BotM (), model)

How to send a message without an extra action?

You can use the helper (<#) that you wrote, with Nothing or NoAction depending on your preference :)

Sorry, but no, that Nothing is inevitable re-issued and triggers handleAction an extra time.

@fizruk
Copy link
Owner

fizruk commented Nov 25, 2020

Why? How can the framework handle this instead of user code?

Even if the user handles this, I think there should be a separate place for it.

But why [BotM action] instead of BotM ()?

The idea was that each BotM action in that list is sort of independent and "atomic" in some sense. A single action might trigger several other things to be done (asynchronously). For example, if the user asks bot something, it can reply instantly, while processing the request in the background and maybe also updating status once in a while. That's an action triggering 3 other things (also as actions), one of which is repeated until the job is done. Current implementation runs BotM actions sequentially and puts second generation actions in a queue which is then processed in the background, but that's an implementation detail.

Sorry, but no, that Nothing is inevitable re-issued and triggers handleAction an extra time.

I do not understand what you mean by "Nothing is inevitable", sorry. Regarding handleAction being triggered one extra time: first of all, this is not directly a problem (you have a check for Nothing/NoAction somewhere anyway), but I can see how putting lots of NoActions into a queue might not be ideal; secondly, this is a performance issue, which was never really considered in this library (the goal was to only present a TEA-like architecture for Telegram bots with some interesting higher-order features like bot transformations, see conversationBot).

On the other hand note that NoOp message/action used in many apps written in Elm (and miso in Haskell) is very similar to NoAction (of course NoAction was inspired by NoOp).

@cblp
Copy link
Author

cblp commented Nov 26, 2020

A single action might trigger several other things to be done (asynchronously).

Well, I didn't expect an asynchronous job framework in a simple bot library.

And it seems to miss exceptions.

For example, if the user asks bot something, it can reply instantly, while processing the request in the background and maybe also updating status once in a while.

As for me, forkIO and async suit better.

@cblp
Copy link
Author

cblp commented Nov 26, 2020

I do not understand what you mean by "Nothing is inevitable", sorry.

When I want to handle just one message and reply to it, I have to emit NoAction after reply, and then I have to handle that NoAction.

One can see in the debug log:

Incoming: SomeAction...
Incoming: NoAction

@swamp-agr
Copy link
Collaborator

Should be fixed in https://hackage.haskell.org/package/telegram-bot-simple-0.4.

  • Maybe Action returned.
  • GetAction existential introduced by @Player-205 to solve even more boilerplate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants