haskell - 不能以“读者”作为字段“强制”数据类型
问题描述
我有以下 Haskell 代码,可以完美编译:
import Control.Monad.Reader (Reader (..))
import Data.Coerce (Coercible, coerce)
data Flow i o = Flow (i -> o) (o -> i)
coerceFlow
:: (Coercible i i', Coercible o o')
=> Flow i o
-> Flow i' o'
coerceFlow = coerce
但是,如果我将Flow
类型的定义更改为以下内容:
data Flow i o = Flow (i -> Reader Int o) (o -> i)
我开始看到一个奇怪的错误:
Coerce.hs:10:14: error:
• Couldn't match type ‘o’ with ‘o'’ arising from a use of ‘coerce’
‘o’ is a rigid type variable bound by
the type signature for:
coerceFlow :: forall i i' o o'.
(Coercible i i', Coercible o o') =>
Flow i o -> Flow i' o'
at Coerce.hs:(6,1)-(9,17)
‘o'’ is a rigid type variable bound by
the type signature for:
coerceFlow :: forall i i' o o'.
(Coercible i i', Coercible o o') =>
Flow i o -> Flow i' o'
at Coerce.hs:(6,1)-(9,17)
• In the expression: coerce
In an equation for ‘coerceFlow’: coerceFlow = coerce
• Relevant bindings include
coerceFlow :: Flow i o -> Flow i' o' (bound at Coerce.hs:10:1)
|
10 | coerceFlow = coerce
| ^^^^^^
据我了解,我的数据类型不再是Coercible
自动的。有没有办法告诉 GHC 我可以Flow
自动强制类型值?我可以coerce
手动输入每个字段,但我想coerce
一次输入整个数据类型(这是DerivingVia
工作所必需的)。
我尝试使用这样的RoleAnnotations
扩展:
type role Flow representational representational
但我看到一个错误:
Coerce.hs:6:1: error:
• Role mismatch on variable o:
Annotation says representational but role nominal is required
• while checking a role annotation for ‘Flow’
|
6 | type role Flow representational representational
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
解决方案
让我们调查一下:
> :info Reader
type Reader r = ReaderT r Data.Functor.Identity.Identity :: * -> *
-- Defined in `Control.Monad.Trans.Reader'
所以,Reader
是根据 来定义的ReaderT
。
> :info ReaderT
type role ReaderT representational representational nominal
newtype ReaderT r (m :: k -> *) (a :: k)
= ReaderT {runReaderT :: r -> m a}
-- Defined in `Control.Monad.Trans.Reader'
...并且ReaderT
在nominal
它的第三个参数中,导致Reader
在nominal
它的第二个参数中,并使你的强制失败。您不能使用您的Flow
类型的角色注释来颠覆这一点,因为这将应付之前的角色注释ReaderT
.
现在,您可能想知道为什么ReaderT
会有nominal
第三个参数。要理解这一点,请考虑其定义:
newtype ReaderT r m a = ReaderT (r -> m a)
上面的 , 应该是什么角色a
?这得看情况。如果m :: * -> *
是representational
在它的论点上,那么ReaderT
是这样的a
。nominal
和 也是如此phantom
。在这里表达角色的“最佳”方式是使用角色多态性,例如
type role forall r .
ReaderT representational (representational :: (* with role r) -> *) r
其中第三个参数的作用取决于第二个更高种类的参数。
唉,GHC 不支持像上面这样的角色多态性,所以我们只能使用限制性最强的角色:nominal
.
推荐阅读
- javascript - 如何检查 Aurelia 中的页面加载是否完成
- javascript - 三次失败登录尝试重定向的计数器不执行任何操作
- android - 静默 Google 登录:为什么选择帐户后显示对话框
- c# - C# - (绘图列 - 右上角)drawString 问题
- css - 如何在具有属性的部分中设置类(css)的样式
- javascript - 如何使用javascript包装h2标签直到在包装器div中找到下一个h2?
- r - 从几个变量中提取中值和置信区间到 R 中的单独表中
- c# - .Net Core - Environment.SetEnvironmentVariable 的位置
- php - MySQLi 插入问题 - PHP 7.2.10
- windows - 提供程序“docker”上的 Win10 上的 Vagrant 2.2 错误