Search code examples
fay

Derive Monad from Fay newtype in order to enable do notation


I want to create a different classes of side-effecty functions, so I can mark some of the side-effects as safer than other ones.

I'd like to create a newtype over the Fay side-effect monad and use it in the do notation, so I declare it like this:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE PackageImports #-}
import "base" Control.Monad
newtype ReadFay a = ReadFay { readFay :: Fay a } deriving Monad

A this point, the compiler cannot find the base package. It is possible to do it in fay somehow?

I can still create my own versions of >>=, return, etc. for the ReadFay, but being able to use it in do notation would be nice.

Or, is there a better way, how to create a different classes of side-effect than this my approach?


Solution

  • Looks like I need to enable

    {-# LANGUAGE RebindableSyntax #-}
    

    to override the functions, that the do notation is calling. Then I need to implement the wrapping and unwrapping to/from the newtype in the functions that I plan to use in the do notation and shadow the Prelude ones:

    myFayReturn :: a -> ReadFay a
    myFayReturn x = ReadFay $ return x
    
    myFayBind :: ReadFay a -> (a -> ReadFay b) -> ReadFay b
    myFayBind = \a b -> ReadFay $ runReadFay a >>= (runReadFay . b)
    
    newtype ReadFay a = ReadFay { runReadFay :: Fay a }
    
    doNotation :: ReadFay ()
    doNotation = let
        x >>= y = myFayBind x y
        return = myFayReturn
        in do
            u <- ReadFay $ putStrLn "A"
            return ()