我正在努力学习Monad,并编写了以下Monad和函数,其中我使用了>>
(在apply
-函数中),尽管它没有在Monad本身中声明。这是如何编译的呢?据我所知,http://learnyouahaskell.com/a-fistful-of-monads#walk-the-line要求在Monad的示例化中声明它,就像Maybe Monad
的情况一样。
data Value =
NoneVal
| TrueVal | FalseVal
| IntVal Int
| StringVal String
| ListVal [Value]
deriving (Eq, Show, Read)
data RunErr = EBadV VName | EBadF FName | EBadA String
deriving (Eq, Show)
newtype CMonad a = CMonad {runCMonad :: Env -> (Either RunErr a, [String]) }
instance Monad CMonad where
return a = CMonad (\_ -> (Right a, []))
m >>= f = CMonad (\env -> case runCMonad m env of
(Left a, strLst) -> (Left a, strLst)
(Right a, strLst) -> let (a', strLst') = runCMonad (f a) env in (a', strLst ++ strLst'))
output :: String -> CMonad ()
output s = CMonad(\env -> (Right (), [] ++ [s]))
apply :: FName -> [Value] -> CMonad Value
apply "print" [] = output "" >> return NoneVal
此外,我如何才能在运行apply时从控制台显示输出(打印输出)呢?目前我得到了以下错误消息,尽管我的类型有derive Show
:
<interactive>:77:1: error:
* No instance for (Show (CMonad Value)) arising from a use of `print'
* In a stmt of an interactive GHCi command: print it
2条答案
按热度按时间cpjpxq1n1#
>>
运算符是可选的,不是必需的。文档中指出,* 最小完整定义 * 是>>=
。虽然您 * 可以 * 实现>>
和return
,但您不必这样做。如果您不提供它们,Haskell可以使用默认的实现,这些实现是从>>
和/或Applicative
的pure
派生的。类型类的定义是(当前GHC源代码,简化为基本要素):
注意
>>=
缺少一个实现,这意味着你 * 必须 * 提供它。另外两个函数有一个默认实现,但是如果你想的话你可以“覆盖”它们。如果你想看到GHCi的输出,类型必须是一个
Show
示例。如果类型 Package 了一个函数,没有明确的方法可以做到。k3bvogb12#
标准Prelude中
Monad
的声明如下:(简化自Prelude来源)它是一个类型类,有三个方法:
(>>=)
、(>>)
和return
。在这三个函数中,有两个有 *default实现 * -函数在类型类中实现,而另一个没有。
Monad
是Applicative
的一个子类,而return
与pure
相同--由于历史原因,它被包含在Monad
类型类中(或根本不包含)。在剩下的两个中,
(>>=)
是在Haskell中定义Monad
所需要的全部。(>>)
可以在类型类之外定义,如下所示:之所以包括这个,是为了防止单子作者希望用更有效的实现来覆盖默认实现。
一个不是必需的类型类方法被称为 optional。
Haddock文档基于没有默认实现的方法自动生成了一个“最小完整定义”。您可以在这里看到
Monad
的最小定义实际上是(>>=)
。有时候,所有的方法都可以有默认的实现,但是它们不是可选的。当必须提供两个方法中的一个,而另一个是根据它定义的时候,就会发生这种情况。
Traversable
类型类就是这种情况,其中traverse
和sequenceA
都是根据对方实现的。不实现任何一个方法都会导致它们进入无限循环。为了标记这一点,GHC提供了
MINIMAL
编译指示,它生成必要的编译器警告,并确保Haddock是正确的。顺便说一句,默认情况下,未能实现所需的类型类方法是一个编译器警告,而不是一个错误,如果调用它,将导致运行时异常。这种行为没有很好的理由。
您可以使用
-Werror=missing-methods
GHC标志更改此默认值。哈斯克林快乐!