我有一个这样定义的新类型Env
:
newtype Env a = Env (State (Context Type) a) deriving (Functor, Applicative, Monad, MonadState (Context Type))
我希望它被自动强制到State (Context Type) is expected
的地方,而没有运行时开销,但是我收到了这个错误:
flip evalState ctx $ Env <$> compile expr
假设编译类型正确,
compile :: a -> Env a
这是错误:
Data constructor not in scope:
Env :: Env Expr -> State (Context Type) c
当然,数据构造函数与newtype构造函数不同,但是如何使evalState
接受Env a
?
答案 0 :(得分:4)
此错误消息表示未导入数据构造函数Env
(与 type 构造函数Env
相对)。这与data
和newtype
之间的区别无关。
data Env = Env (...) -- Same terminology
newtype Env = Env (...) -- for both
-- ^ ^
-- | data constructor
-- type constructor
检查您的导入语句(它们是否合格?是否使用显式导入列表?)以及您的导出列表。特别是,这是一个常见的混淆点:
-- data constructor hidden
module Bar (Env, ...) where -- only exports the type constructor
-- data constructor exported
module Bar (Env(Env), ...) where
-- or --
module Bar (Env(..), ...) where -- these do export both the type and data constructor Env
然后,一旦Env
处于范围内,您仍然会遇到类型错误,因为Env
的类型为State (Context Type) a -> Env a
,但是它被应用于Expr
(假设这就是expr
的类型。您需要改为解构Env
:
runEnv :: Env a -> State (Context Type) a
runEnv (Env f) = f
-- or, in the definition of Env
newtype Env a = Env { runEnv :: State (Context Type) a } deriving ...
所以你可以写
flip evalState ctx (runEnv (compile expr))
如果您将runEnv
明确定义为一个函数,则也可以将evalState
重构为一个函数:
runEnv :: Context Type -> Env a -> a
runEnv ctx (Env f) = evalState f ctx
---
runEnv ctx (compile expr) :: Expr