Giter VIP home page Giter VIP logo

Comments (4)

HeinrichApfelmus avatar HeinrichApfelmus commented on June 25, 2024

Thanks for the suggestion!

In what context did you write it?

I'm not entirely sure if I want it. My reasoning is that Program should make it easier to write your own monads. However, as soon as you use the interpretWithMonadT function, chances are that you have already written your monad — it's the thing that you map to! In that case, building the Program thing was probably superfluous.

That said, it might be useful for writing multiple interpreters, some being bases on traditional monads.

from operational.

andrewthad avatar andrewthad commented on June 25, 2024

It's actually just a function that I stumbled upon as I was playing around with operational. My uses are probably a little different than yours though. What I'm doing is taking instructions, transforming them into another set of instructions, and then turning them into IO:

ProgramT AccelopsApi m a  ==>  ProgramT HttpI m a  ==>  IO a

The HttpI instruction is similar to a data type from free-http and tries to solve a similar problem. The main thing that I'm doing that free-http doesn't attempt is logging. I've written a function interpretWithLogging:

interpretWithLogging :: forall instr m b. Monad m
  => (forall a instr a -> (m (), a -> m ()))   -- ^ Tuple has before and after logs
  -> (forall a. instr a -> m a) -> ProgramT instr m b -> m b

So that I can actually attach logging behaviors to a program at the time that the interpreter is given. I can apply this at both interpretation steps to get (1) a log of the higher level description of what API calls I am making and (2) an log of all the HTTP traffic. I think that I may be able to do replays with this but I'm not sure yet.

So, in short the function interpretWithMonadT is actually a degenerate case of interpretWithLogging in which the logging function does nothing.

from operational.

andrewthad avatar andrewthad commented on June 25, 2024

Just reflecting this a little more, I think that I tend to see operational as a way to do safer and more restricted IO. Consequently, my goal is always to reduce the instructions to an IO action. By contrast, it sounds like your main goal is to create real monads. In the examples directory you provided, all of your examples except for TicTacToe.hs are about more legitimate non-IO monads. It's kind of cool that the same code you intend for a specific purpose can be so useful in different contexts as well.

from operational.

HeinrichApfelmus avatar HeinrichApfelmus commented on June 25, 2024

By contrast, it sounds like your main goal is to create real monads. In the examples directory you provided, all of your examples except for TicTacToe.hs are about more legitimate non-IO monads.

Actually, it depends. In the end, you have to map to some type anyway, which can be a plain type or IO. What makes operational useful are these two things:

  1. Write monads without having to come up with the right type that is suitable to implement (>>=).
  2. Use multiple interpretations for the same instruction set.

And I think you're making good use the second point with the interpretWithLogging function. It allows you to separate the "executable behavior" from the "logging behavior" of each instruction, e.g.

exec (Get s) = Data.Map.lookup s <$> readIORef pages
exec …

log (Get s) = (putStrLn "Get returned", print)
log …

If you would implement the instruction Get as a single function get, then both would have to be in the same place in the source code; here you can separate them with the exec and the log function, and put them into different modules, for example. (Well, you can always write separate functions logGet and execGet, but using an ADT is more systematic.)

On the other hand, the interpretWithMonadT function makes use of neither capability, so I would like to refrain from adding it to the API. I think this makes it easier for newcomers to avoid "misuse" of the package, in the sense that they look at the types and combine functions in a way that is of no real benefit to them. ("Ah, I want to end with a monad, so I use this function, which means I have to implement a monad like this…")

from operational.

Related Issues (17)

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.