没有因使用“打印”而产生的 (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 -> ..
.
我是 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 -> ..
.