I have module:
module Writer where
import Prelude hiding (Monad, (>>=), return, (=<<))
main = putStrLn "hello"
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(=<<) :: (a -> m b) -> m a -> m b
(=<<) = flip (>>=)
data Writer w a = Writer { runWriter :: (a, w) } deriving Show
instance (Monoid w) => Monad (Writer w) where
return x = Writer $ (x, mempty)
m >>= k = let
(b, w1) = runWriter m
Writer (a, w2) = k b
in Writer (a, (w1 `mappend` w2))
writer :: (a, w) -> Writer w a
writer = Writer
instance (Semigroup a, Num a) => Monoid (Foo a) where
mempty = Foo 0
mappend (Foo v1) (Foo v2) = Foo (v1 + v2)
instance Semigroup a => Semigroup (Foo a) where
(Foo v1) <> (Foo v2) = Foo (v1 <> v2)
instance Semigroup Integer where
a1 <> a2 = a1 + a2
tell :: Monoid w => w -> Writer w ()
tell w = writer ((), w)
data Foo a = Foo { getFoo :: a } deriving Show
type LoggerFooInt = Writer (Foo Integer) ()
logLine :: String -> Integer -> LoggerFooInt
logLine _ = tell . Foo
batchLog :: Writer (Foo Integer) ()
batchLog = do
logLine "line1" 19450
logLine "line2" 760
logLine "line3" 218
I tried to write batchLog function but compiler said:
Writer.hs:46:3: error:
• No instance for (GHC.Base.Monad (Writer (Foo Integer)))
arising from a do statement
• In a stmt of a 'do' block: logLine "line1" 19450
In the expression:
do logLine "line1" 19450
logLine "line2" 760
logLine "line3" 218
In an equation for ‘batchLog’:
batchLog
= do logLine "line1" 19450
logLine "line2" 760
logLine "line3" 218
|
46 | logLine "line1" 19450
| ^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
So, why I need to define any Monads else. I have already instance (Monoid w) => Monad (Writer w) and instance (Semigroup a, Num a) => Monoid (Foo a) and instance Semigroup Integer. Why it's not enough? Without batchLog function module compiles.
GHCi, version 8.6.5: http://www.haskell.org/ghc/
UPDATE: I tried to rewrite without do notation, and after a while I can do that and it compiles, but still can't understand, why another code, compiles with my own Monad and with do notation:
module MaybeMonad
import Prelude hiding (Monad, (>>=), return, (=<<))
import Control.Monad (ap, liftM)
import Data.Char
main = putStrLn "hello"
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(=<<) :: (a -> m b) -> m a -> m b
instance Monad Maybe where
return = Just
(>>=) Nothing _ = Nothing
(>>=) (Just x) k = k x
(=<<) = flip (>>=)
data Token = Number Int | Plus | Minus | LeftBrace | RightBrace
deriving (Eq, Show)
asToken :: String -> Maybe Token
asToken "+" = Just(Plus)
asToken "-" = Just(Minus)
asToken "(" = Just(LeftBrace)
asToken ")" = Just(RightBrace)
asToken str | all isDigit str = Just $ Number $ read str
asToken _ = Nothing
tokenize :: String -> Maybe [Token]
tokenize x = foldr (\word maybeTokens -> do
token <- asToken word
tokens <- maybeTokens
return $ token : tokens) (return []) $ words x
Correct example:
{-# LANGUAGE RebindableSyntax #-}
module Writer where
import Prelude hiding (Monad, (>>=), return, (=<<), (>>))
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(=<<) :: (a -> m b) -> m a -> m b
(=<<) = flip (>>=)
(>>) :: m a -> m b -> m b
data Writer w a = Writer { runWriter :: (a, w) } deriving Show
instance (Monoid w) => Monad (Writer w) where
return x = Writer $ (x, mempty)
m >>= k = let
(b, w1) = runWriter m
Writer (a, w2) = k b
in Writer (a, (w1 `mappend` w2))
ma >> mb = let
(_, w1) = runWriter ma
(vb, w2) = runWriter mb
in Writer(vb, (w1 `mappend` w2))
writer :: (a, w) -> Writer w a
writer = Writer
instance (Semigroup a, Num a) => Monoid (Foo a) where
mempty = Foo 0
mappend (Foo v1) (Foo v2) = Foo (v1 + v2)
instance Semigroup a => Semigroup (Foo a) where
(Foo v1) <> (Foo v2) = Foo (v1 <> v2)
instance Semigroup Integer where
a1 <> a2 = a1 + a2
tell :: Monoid w => w -> Writer w ()
tell w = writer ((), w)
data Foo a = Foo { getFoo :: a } deriving Show
logLine :: String -> Integer -> Writer (Foo Integer) ()
logLine _ = tell . Foo
batchLog :: Writer (Foo Integer) ()
batchLog = do
logLine "line1" 19450
logLine "line2" 760
logLine "line3" 218
after adding RebindableSyntax and hiding (>>) operator and adding my own realization it compiles and works properly.
As per @freestyle's comment, do-notation by design always uses the Monad class from Prelude, even if you have your own Monad class defined. The RebindableSyntax extension can be enabled to make do-notation use whatever Monad class (or more specifically, whatever >>=, >>, and fail functions) are currently in scope.
This also affects a bunch of other rebindable syntax. See the link above for a list, and make sure you aren't overriding additional syntax you don't intend to.
Also, RebindableSyntax implies NoImplicitPrelude, but that should be fine since you already have an import Prelude statement.
UPDATE: However, it's important to make sure you've hidden ALL the applicable Prelude syntax, or you may find yourself unintentionally using the Monad class from Prelude, even if you didn't want to. In your definition of:
batchLog :: Writer (Foo Integer) ()
batchLog = do
logLine "line1" 19450
logLine "line2" 760
logLine "line3" 218
the do-block is desugared into:
batchLog = logLine "line1" 19450 >> logLine "line2" 760 >> ...
And, where is (>>) defined? In Prelude, of course. You will need to hide that as well, and provide your own definition, either in your custom Monad class or as a standalone function. After making the following modifications to your first code block, the do-block type checks correctly, and runWriter batchLog appears to work fine:
import Prelude hiding (..., (>>), ...)
(>>) :: (Monad m) => m a -> m b -> m b
act1 >> act2 = act1 >>= \_ -> act2