Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do notation without monads: possible?

Tags:

I have a stateful type with the >> and >>= operators, which is nearly a monad. The intended use is to generate code for another language, and having the do-notation available will be very appropriate.

However, there is no well-defined return function, as values are only supposed to be produced along with side-effects. So, if I fake a return function, the return function should return an error only, and it breaks the monad laws. ( I.e. it is never valid to use a return function. )

What I observe is that the do-notation only sugars two operators, the >> and >>= operators.

Is there a way to retain something like the do notation for only those 2 operators, or something as clean as it, but without making a monad?

NOTE: Below the line are details that are not necessary for the question in the title. It's the context for why I asked the question, replies to which I'm interested in. Others who browse this topic would probably prefer to ignore it.


CORRECTION: I'm not generating code into an imperative language, although it shouldn't matter. I'm generating code into Javascript.

CLARIFICATION (in response to bdonlan): My type is (m a), which carries a state (which is the code to be generated given various parameters, similar to the state monad) and will return a value (the variable names in the generated code, with a haskell type attached). Thus, there shouldn't be a way to return values, which are associated with variable names, without generating code that defines the variable names. * This is solely due to my design, which might be inferior to others which I have not thought of.

In response to the responses: There seems to be two kinds of responses to this. First, is whether it is indeed possible, and perhaps the best way to go about using the do notation. The second is on whether it is better to use a monad, and define a return (or whether it even makes sense to not do so - perhaps at a later point in time, I would find that a return is required).

Example of what I would be doing:

data JsState = JsState { code :: String , vidCount :: Int }  -- vidCount is for generating unique variable names  newtype JsStmt = JsStmt ( JsState -> JsState )  newtype JsMonad a = JsMonad ( JsState -> ( a , JsState ) )  def :: (JsValue a) => a -> JsMonad a  -- Outputs "var " ++ toUniqueVarName vidCount ++ " = " toCode a ++ ";"  -- Returns JsMonad with the variable name as the value, -- with a type attached, and the JsState's vidCount is incremented by 1.   alertJsInt :: JsIntE -> JsMonad ()  -- Outputs something like "alert(" ++ toCode JsIntE ++ ");"  do   x <- def $ JsIntL 2   y <- def $ JsIntL 4   alertJsInt (x + y) 
like image 657
Dingfeng Quek Avatar asked Jun 22 '11 00:06

Dingfeng Quek


People also ask

Why is monad useful?

monads are used to address the more general problem of computations (involving state, input/output, backtracking, ...) returning values: they do not solve any input/output-problems directly but rather provide an elegant and flexible abstraction of many solutions to related problems.

How do monads work?

So in simple words, a monad is a rule to pass from any type X to another type T(X) , and a rule to pass from two functions f:X->T(Y) and g:Y->T(Z) (that you would like to compose but can't) to a new function h:X->T(Z) . Which, however, is not the composition in strict mathematical sense.

What is monad condition?

A monad is essentially just a functor T with two extra methods, join , of type T (T a) -> T a , and unit (sometimes called return , fork , or pure ) of type a -> T a .

Why are monads useful Haskell?

A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.


1 Answers

Well, the sort of structure you're working with does already exist; a relevant type class can be found on Hackage, in fact. I don't recommend trying to force it into an instance of Monad, though, for the reasons that bdonlan gives. The existence of return is pretty fundamental and you're likely to run into trouble everywhere trying to use standard functions for Monads.

....however! That said, if you really want do notation, consider this quote from the GHC user guide:

"Do" notation is translated using whatever functions (>>=), (>>), and fail, are in scope (not the Prelude versions).

...in other words, you're right that using do notation makes sense, because nowhere does it actually use return when desugared. That section is about the RebindableSyntax extension, which does exactly what it claims. If you don't mind giving up do notation for Monad, you can use that extension, define your own functions, and use do notation all you like.

like image 50
C. A. McCann Avatar answered Oct 19 '22 07:10

C. A. McCann