考虑以下 Haskell 代码:
import Data.Coerce
newtype Decorated s a = Decorated a
fancyFunction :: Ctx s => f (Decorated s a) -> r
fancyFunction = ...
instance Ctx s => SomeClass (Decorated s a)
myFunction :: Functor f => f a -> r
myFunction = fancyFunction . fmap coerce
我想通过将 fmap coerce
替换为 coerce
来使 myFunction
更快。基本原理是,coerce
的行为类似于 id
,仿函数法则之一是 fmap id = id
。
我能想到的唯一方法是将 Coercible (f a) (f (Decolated s a)) 添加到上下文中,但它引用的 s 没有在其他任何地方引用。更糟糕的是,如果 a
绑定(bind)在通用类型中,我无法表达该约束。是否有一个约束我可以用 f
来表达,只让我使用 coerce
在 f a
和 f (装饰 s a )
?
这是编译器根据 f
是仿函数这一事实自行计算出来的吗?如果是这样,它是否也适用于 bifunctors、traversables 和 bittraverables?
最佳答案
不幸的是,Coercible (f a) (f (Decorated s a))
考虑到 GHC 的当前状态,您确实想要在约束中得到什么。现在,事实是s
和a
不出现在其他地方并不是什么好事 - 这意味着 GHC 不知道如何处理它们(它们是模棱两可的)!我不会涉及这个...
取决于role提供给类型构造函数的类型参数 f
, Coercible a b
可能暗示也可能不暗示Coercible (f a) (f b)
。在这种情况下,我们希望该角色是名义上的 - 但(至少)还没有一种方法可以在约束中表达这一点。为了解释我的意思,请考虑以下两个数据定义:
{-# LANGUAGE TypeFamilies #-}
import Data.Coerce
-- type role of `a` is "representational"
data Data1 a = Data1 a
-- type role of `a` is "nominal"
data Data2 a = Data2 (TypeFunction a)
type family TypeFunction x where
TypeFunction Bool = Char
TypeFunction _ = ()
那么,虽然 Coercible a b
确实如此需要Coercible (Data1 a) (Data1 b)
,它不需要 Coercible (Data2 a) (Data2 b)
。为了使这一点具体化,请在 GHCi 中加载上述内容,然后尝试:
ghci> newtype MyInt = My Int
ghci> let c1 = coerce :: (Data1 MyInt) -> (Data1 Int)
ghci> let c2 = coerce :: (Data2 MyInt) -> (Data2 Int) -- This doesn't work!
不幸的是,没有基于内置约束的方法来强制类型变量的角色具有代表性。您可以为此创建自己的类(class),如 Edward Kmett has done ,但 GHC 不会像 Coercible
的类实例那样自动创建其中一些类的实例。是。
这导致了 this trac 票,他们在其中讨论类的可能性 Representational f
生成的实例类似于 Coercible
其中可能有类似的内容
instance (Representational f, Coercible a b) => Coercible (f a) (f b)
如果这确实是今天的事情,那么您在约束中所需要的就是 Representational f
。此外,正如理查德·艾森伯格在罚单上观察到的那样,我们确实应该能够弄清楚 a
在f a
对于任何合理的仿函数都具有代表性作用f
。然后,我们甚至可能不需要 Functor f
之上的任何约束如Representational
可能是 Functor
的父类(super class).
Here is a good discussion of the current limitations of roles.
关于haskell - 如何强制应用于可强制参数的仿函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39522041/