没有使用"print"引起的(Show(Eval Int))的实例



我是哈斯克尔的新手,正在修改Stephen Diehl的《我希望我在学习哈斯克尔时知道什么》中的一些例子。

我一直停留在这个monad转换器的例子上:原始代码。

即使在将代码简化到最低限度之后,我也未能找出错误的原因。我还研究了SO上的其他问题,这些问题看起来很相似,但问题的原因似乎不同。

这是简化的代码:

import Control.Monad.Reader
type Env = [(String, Int)]
type Eval a = ReaderT Env Maybe a
data Expr 
= Val Int
| Var String
deriving (Show)
eval :: Expr -> Eval Int
eval ex = case ex of
Val n -> return n

代码编译正确,但一旦我运行eval (Val 5)GHCi,就会输出以下错误。

Prelude> eval (Val 5)
<interactive>:135:1: error:
• No instance for (Show (Eval Int)) arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it

谢谢。

不能打印类型为Eval Int的值,因为它被定义为ReaderT Env Maybe Int。打印该类型的值本质上相当于打印函数Env -> Maybe Int,并且函数无法打印。

考虑使用调用函数

runReaderT (eval (Val 5)) []

其中CCD_ 5以上代表评估环境。

这并不是没有道理的,事实上它帮助我避免了将newtype包装/展开与实际数据混淆。

如果我们将ReaderT定义为类型同义词,而不是newtype,那么它是一个我们可以直接应用的函数

type MyReaderT :: Type -> (Type -> Type) -> Type -> Type
type MyReaderT a m b = a -> m b
mypure :: Applicative f => b -> MyReaderT a f b
mypure b _a = pure b

你的eval变成

type Eval :: Type -> Type
type Eval b = MyReaderT Env Maybe b

展开MyReaderT:

type Eval :: Type -> Type
type Eval b = Env -> Maybe b
eval :: Expr -> Eval Int
eval (Val n) = mypure n

你可以直接通过环境

myeval (Val 3)
:: Env -> Maybe Int
myeval (Val 3) [("x", 4)]
= Just 3
:: Maybe Int

我的建议,尤其是对于monad转换器,是实现所有内容的my*版本。newtype允许我们编写实例,我们不能为MyReaderT ..编写任何常见的实例,但它可以让您更接近实际问题。

对我来说,我在学校很难理解这样的东西

type Time :: Type
type Time = Double
type    Signal :: Type -> Type
newtype Signal a = Sig { unSig :: Time -> a }

需要告诉我,我们需要newtype作为实例,而Signal ..只是封装了Time -> ..

最新更新