haskell - 为什么我必须按字段而不是一次强制这种数据类型?
问题描述
我有两种类型(<->)
并(<-->)
表示类型之间的同构:
data Iso (m :: k -> k -> *) a b = Iso { to :: m a b, from :: m b a }
type (<->) = Iso (->)
infix 0 <->
data (<-->) a b = Iso' { to' :: a -> b, from' :: b -> a }
infix 0 <-->
两者之间的唯一区别是(<->)
更通用类型的专业化。
我可以coerce
(<-->)
很容易地同构:
coerceIso' :: (Coercible a a', Coercible b b') => (a <--> b) -> (a' <--> b')
coerceIso' = coerce
但是当我尝试使用(<->)
同构时出现错误:
coerceIso :: (Coercible a a', Coercible b b') => (a <-> b) -> (a' <-> b')
coerceIso = coerce
{-
src/Data/Iso.hs:27:13: error:
• Couldn't match type ‘a’ with ‘a'’ arising from a use of ‘coerce’
‘a’ is a rigid type variable bound by
the type signature for:
coerceIso :: forall a a' b b'.
(Coercible a a', Coercible b b') =>
(a <-> b) -> a' <-> b'
at src/Data/Iso.hs:25:1-73
‘a'’ is a rigid type variable bound by
the type signature for:
coerceIso :: forall a a' b b'.
(Coercible a a', Coercible b b') =>
(a <-> b) -> a' <-> b'
at src/Data/Iso.hs:25:1-73
-}
我目前的解决方法是分别强制执行前进和后退功能:
coerceIso :: (Coercible a a', Coercible b b') => (a <-> b) -> (a' <-> b')
coerceIso (Iso f f') = Iso (coerce f) (coerce f')
但是为什么需要这样的解决方法呢?为什么不能(<->)
直接强制?
解决方案
问题在于m
您的一般Iso
类型中参数的角色。
考虑:
data T a b where
K1 :: Int -> T () ()
K2 :: String -> T () (Identity ())
type (<->) = Iso T
你不能真的期望能够转换T () ()
成T () (Identity ())
即使()
并且Identity ()
是强制性的。
你需要类似(伪代码):
type role m representational representational =>
(Iso m) representational representational
但我相信,这在当前的 Haskell 中是做不到的。
推荐阅读
- java - 实践中的 Java 并发:清单 8.3。诱导锁排序以防止死锁
- android - Admob 测试插页式广告显示但不是真实广告
- c - 如何在不了解结构的情况下学习回溯递归?- C
- google-apps-script - 用于复制单元格并添加复制日期和时间的脚本
- postgresql - 使用 amqp 扩展从 PostgreSQL 向 RabbitMQ 发布消息时出错 - 在代理 1 上登录失败
- php - 雄辩的 groupBy 但只分组 ONE 行
- macos - 如何在 Mac 中将 SMB 共享与不同用户连接?
- javascript - 在 Sortable 中设置默认排序列
- python - 获取轮廓与其凸包之间的差异列表
- powershell - PowerShell 脚本在本地工作,但不能在远程工作