首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >不能‘强制’使用'Reader‘作为字段的数据类型

不能‘强制’使用'Reader‘作为字段的数据类型
EN

Stack Overflow用户
提问于 2020-05-17 00:42:10
回答 2查看 138关注 0票数 10

我有以下Haskell代码,可以很好地编译:

代码语言:javascript
运行
复制
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类型的定义更改为以下内容:

代码语言:javascript
运行
复制
data Flow i o = Flow (i -> Reader Int o) (o -> i)

我开始看到一个奇怪的错误:

代码语言:javascript
运行
复制
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扩展,如下所示:

代码语言:javascript
运行
复制
type role Flow representational representational

但我发现了一个错误:

代码语言:javascript
运行
复制
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
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-17 01:24:53

让我们来调查一下:

代码语言:javascript
运行
复制
> :info Reader
type Reader r = ReaderT r Data.Functor.Identity.Identity :: * -> *
        -- Defined in `Control.Monad.Trans.Reader'

因此,Reader是用ReaderT定义的。

代码语言:javascript
运行
复制
> :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第三个参数。要理解这一点,请考虑它的定义:

代码语言:javascript
运行
复制
newtype ReaderT r m a = ReaderT (r -> m a)

上面提到的a应该扮演什么角色?好吧,这要看情况。如果m :: * -> *在其参数上为representational,那么ReaderTa上也是如此。nominalphantom也是如此。在这里表达角色的“最佳”方式是使用角色多态性,比如

代码语言:javascript
运行
复制
type role forall r .
     ReaderT representational (representational :: (* with role r) -> *) r

其中第三个论元的作用取决于第二个更高层次的论元。

遗憾的是,GHC不支持像上面这样的角色多态性,所以我们只能使用最具限制性的角色:nominal

票数 5
EN

Stack Overflow用户

发布于 2020-05-17 07:32:39

如果你避免使用ReaderT,而使用教科书上的(->) r monad,这个问题就不再是问题了,@chi解释道:

代码语言:javascript
运行
复制
{-# LANGUAGE FlexibleContexts #-}
module Foo where
import Data.Coerce (Coercible, coerce)

newtype RT r o = RT { runR :: r -> o }
data Flow i o = Flow (i -> RT Int o) (o -> i)

coerceFlow
    :: (Coercible i i', Coercible o o')
    => Flow i o
    -> Flow i' o'
coerceFlow = coerce
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61840227

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档