调用newtype构造函数

时间:2019-02-28 23:37:32

标签: haskell

我有一个这样定义的新类型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

1 个答案:

答案 0 :(得分:4)

此错误消息表示未导入数据构造函数Env(与 type 构造函数Env相对)。这与datanewtype之间的区别无关。

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