我有模块:
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
我试图编写batchLog
函数,但编译器说:
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.
那么,为什么我需要定义其他任何 Monad。我已经instance (Monoid w) => Monad (Writer w)
和instance (Semigroup a, Num a) => Monoid (Foo a)
和instance Semigroup Integer
。为什么还不够?没有batchLog
功能模块编译。
GHCi,版本 8.6.5:http ://www.haskell.org/ghc/
更新: 我尝试在不使用 do 表示法的情况下进行重写,过了一段时间我可以这样做并且它编译,但仍然无法理解,为什么另一个代码使用我自己的 Monad 和 do 表示法编译:
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
正确的例子:
{-# 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
添加 RebindableSyntax 和隐藏 (>>) 运算符并添加我自己的实现后,它可以编译并正常工作。