没有因使用“打印”而产生的 (Show (Eval Int)) 实例

No instance for (Show (Eval Int)) arising from a use of ‘print’

我是 Haskell 的新手,正在修改 Stephen Diehl 的《学习时我希望知道的事》中的一些示例 Haskell。

我被困在这个 monad 转换器示例上:original code

即使将代码简化到最低限度,我也未能将错误原因归零。我还在 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)) []

[]上方代表评估环境。

这并非不合理,事实上它帮助我避免将新类型 wrapping/unwrapping 与实际数据混淆。

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

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 -> ...